标签:dp
5 6 2 8 7 1 0 5 2 10 20 0
10HintIn the sample, there is two ways to achieve Xiaoji‘s goal. [6 2 8 7 1] -> [8 8 7 1] -> [8 8 8] will cost 5 + 5 = 10. [6 2 8 7 1] -> [24] will cost 20.
分析:由于题目要求把原数列变成回文数列,所以只需要找出原数组中的关键点,然后利用这些关键点进行dp。
所谓的关键点就是指数对(i,j)满足v1+v2+……+vi = vj+……+vn。因为关键点i和j是一一对应的,所以一维dp就能解决问题。则dp[i] = min(dp[j-1]+a[l_num[j,i]]+a[r_num[j,i]]|1<=j<=i),其中l_num[j,i]表示左边第j个关键点到第i个关键点的元素个数的总数,r_num[j,i]表示右边第j个关键点到第i个关键点的元素个数的总数
#include<cstdio> #include<algorithm> using namespace std; #define INF 0x3fffffff const int N = 5005; int n, v[N], a[N]; int dp[N]; int L[N], R[N], num; //L[]和R[]记录关键点 void Init() { num = 0; int l = 1, r = n, l_num = 1, r_num = 1; int l_val = v[1], r_val = v[n]; while(l < r) { if(l_val < r_val) { l_val += v[++l]; l_num++; } else if(l_val > r_val) { r_val += v[--r]; r_num++; } else { L[++num] = l_num; R[num] = r_num; l_num = r_num = 1; l_val = v[++l]; r_val = v[--r]; } } } int main() { while(~scanf("%d",&n) && n) { for(int i = 1; i <= n; ++i) scanf("%d",&v[i]); for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); Init(); for(int i = 1; i <= num; i++) { int num1 = 0, num2 = 0; dp[i] = INF; for(int j = i; j >= 1; --j) { num1 += L[j]; num2 += R[j]; dp[i] = min(dp[i], dp[j-1] + a[num1] + a[num2]); } } int ans = a[n], cnt = n; for(int i = 1; i <= num; ++i) { cnt -= L[i] + R[i]; ans = min(ans, dp[i] + a[cnt]); } printf("%d\n", ans); } return 0; }
hdu 4960 Another OCD Patient(dp)2014多校训练第9场,布布扣,bubuko.com
hdu 4960 Another OCD Patient(dp)2014多校训练第9场
标签:dp
原文地址:http://blog.csdn.net/lyhvoyage/article/details/38708245