HDU 4960 Another OCD Patient
2014-08-20 17:45
495 查看
题意:给出一串数字,让你对相邻的几项合并,使最后合并后的序列为对称的序列。同时对不同个数的数字合并有个不同的费用。求最小的消耗费用。
思路:比赛中总是想如何求出对称的序列,怎么也想不出办法。其实,若对称的话,左右两端的序列必须各有一段和是相同的,而且这个子序列是固定的。如果想到这一个点。题目就简单了。
首先,我们可以预处理出左右两端子序列和相等的位置。这些节点就是让合并后的序列为对称序列的关键节点.
我们对关键节点进行标号,左右两端的关键节点形成一对,同时保存和上一个关键节点的长度(即能形成对称的子序列的长度)
对于每个节点,我们可以求出当序列处理到该处时,所需的最小费用。
则dp[i] = min(dp[j] + a[suml[i] - sum[j]] + a[sumr[i] - sumr[j]])
其中:suml[i]表示到左端第i个关键节点的左面的数字的个数,sumr[i]表示到右端第i个关键节点的右面的数字的个数。
而,最终的结果,就是对于每个dp[i], dp[i] + 剩余节点直接全部合成一个数的费用 , 中的最小值。
这里还有一个小的问题,因为对称性分为奇对称和偶对称,这里该如何处理?在这里,其实我们可以把偶对称看做在整个序列关于中间的空的序列的奇对称,就可以用上面的方法解。
代码如下:
思路:比赛中总是想如何求出对称的序列,怎么也想不出办法。其实,若对称的话,左右两端的序列必须各有一段和是相同的,而且这个子序列是固定的。如果想到这一个点。题目就简单了。
首先,我们可以预处理出左右两端子序列和相等的位置。这些节点就是让合并后的序列为对称序列的关键节点.
我们对关键节点进行标号,左右两端的关键节点形成一对,同时保存和上一个关键节点的长度(即能形成对称的子序列的长度)
对于每个节点,我们可以求出当序列处理到该处时,所需的最小费用。
则dp[i] = min(dp[j] + a[suml[i] - sum[j]] + a[sumr[i] - sumr[j]])
其中:suml[i]表示到左端第i个关键节点的左面的数字的个数,sumr[i]表示到右端第i个关键节点的右面的数字的个数。
而,最终的结果,就是对于每个dp[i], dp[i] + 剩余节点直接全部合成一个数的费用 , 中的最小值。
这里还有一个小的问题,因为对称性分为奇对称和偶对称,这里该如何处理?在这里,其实我们可以把偶对称看做在整个序列关于中间的空的序列的奇对称,就可以用上面的方法解。
代码如下:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAX = 5050; long long a[MAX]; long long v[MAX]; long long s1[MAX]; long long s2[MAX]; long long sum1[MAX]; long long sum2[MAX]; int sz; int odd; long long dp[MAX]; int N; void pre_work() { sz = odd =0; int begin = 1, end = N; int lsum = a[begin], rsum = a[end]; while(true){ int l = begin,r = end; while(l != r && lsum != rsum){ if(lsum < rsum) lsum += a[++l]; else if(rsum < lsum) rsum += a[--r]; } if(l == r){ odd = end - begin + 1; return; } else{ s1[++sz] = l - begin + 1; s2[sz] = end - r + 1; if(r == l + 1) return; begin = l + 1; end = r - 1; lsum = a[begin]; rsum = a[end]; } } } int main(void) { //freopen("input.txt","r",stdin); while(scanf("%d",&N)&&N){ for(int i = 1; i <= N; ++i) scanf("%I64d", a+i); for(int i = 1 ; i <= N; ++i) scanf("%I64d",v + i); pre_work(); sum1[0] = sum2[0] = 0; for(int i = 1; i <= sz; ++i){ sum1[i] = sum1[i-1] + s1[i]; sum2[i] = sum2[i-1] + s2[i]; } //for(int i = 1; i <= sz; ++i) // printf("%I64d %I64d\n",sum1[i],sum2[i]); if(sz == 0){ printf("%I64d\n",v ); continue; } memset(dp,0x3f,sizeof(dp)); long long ans = 0x3f3f3f3f3f3f3f3f; dp[0] = 0; for(int i = 1; i <= sz; ++i){ for(int j = 0; j < i; ++j) dp[i] = min(dp[i],dp[j] + v[sum1[i] - sum1[j]] + v[sum2[i] - sum2[j]]); ans = min(ans,dp[i] + v[N - sum1[i]- sum2[i]]); //printf("%d\n",ans); } //for(int i = 1; i <= sz; ++i) // printf("%I64d\n",dp[i]); printf("%I64d\n",ans); } return 0; }
相关文章推荐
- HDU 4960 Another OCD Patient (dp)
- hdu 4960 Another OCD Patient(DP)
- HDU 4960 Another OCD Patient(DP)
- HDU-4960 Another OCD Patient (DP)
- HDU 4960 Another OCD Patient 区间dp
- Another OCD Patient HDU - 4960 (dp+前缀和)
- hdu 4960 Another OCD Patient (最短路 解法
- HDU 4960 Another OCD Patient(记忆化搜索)
- hdu 4960 Another OCD Patient(dp)2014多校训练第9场
- hdu 4960 Another OCD Patient dp(记忆化搜索)
- hdu 4960 Another OCD Patient(记忆化)
- hdu 4960 Another OCD Patient(动态规划)
- hdu 4960 Another OCD Patient(dp)2014多校训练第9场
- hdu 4960 Another OCD Patient dp(记忆化搜索)
- hdu 4960 Another OCD Patient 2014 Multi-University Training Contest 9
- HDU 4960 Another OCD Patient(区间dp记忆化搜索)
- HDU 4960 Another OCD Patient(记忆化搜索)
- hdu 4960 Another OCD Patient 多校九 区间DP
- HDU 4960:Another OCD Patient
- hdu 4960 Another OCD Patient