HDU-4960 Another OCD Patient (DP)

77 篇文章 0 订阅

Another OCD Patient

http://acm.hdu.edu.cn/showproblem.php?pid=4960

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)


Problem Description
Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xiaoji is an OCD patient, he can't stand with the disorder of the volume of the N pieces of plasticene. Now he wants to merge some successive pieces so that the volume in line is symmetrical! For example, (10, 20, 20, 10), (4,1,4) and (2) are symmetrical but (3,1,2), (3, 1, 1) and (1, 2, 1, 2) are not.

However, because Xiaoji's OCD is more and more serious, now he has a strange opinion that merging i successive pieces into one will cost ai. And he wants to achieve his goal with minimum cost. Can you help him?

By the way, if one piece is merged by Xiaoji, he would not use it to merge again. Don't ask why. You should know Xiaoji has an OCD.
 

Input
The input contains multiple test cases.

The first line of each case is an integer N (0 < N <= 5000), indicating the number of pieces in a line. The second line contains N integers Vi, volume of each piece (0 < Vi <=10^9). The third line contains N integers ai  (0 < ai <=10000), and a1 is always 0. 

The input is terminated by N = 0.
 

Output
Output one line containing the minimum cost of all operations Xiaoji needs.
 

Sample Input
  
  
5 6 2 8 7 1 0 5 2 10 20 0
 

Sample Output
  
  
10
Hint
In 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.

题目大意:一个含有n个数点序列,可以合并任意i个连续点数,花费为a[i],寻找最终结果序列是回文时点最小花费


这个题只要想到抓住前缀和与后缀和相等的点进行dp就很容易了(依旧想不到。。。)

首先找出所有点i对称点opp[i](区间不相交),对称点的初值为:dp[i]=a[i]+a[n-opp[i]+1],然后再通过i前面点对称点j对其进行更新

最后注意对称点间点区间[i,opp[i]]也可以进行合并

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=5005;

int n,num;
int v[MAXN],a[MAXN],opp[MAXN];
long long prefix[MAXN],suffix[MAXN],dp[MAXN],ans;

int main() {
    freopen("in.txt","r",stdin);
    while(scanf("%d",&n),n!=0) {
        prefix[0]=suffix[0]=suffix[n+1]=0;
        for(int i=1;i<=n;++i) {
            scanf("%d",v+i);
            prefix[i]=prefix[i-1]+v[i];//计算v的前缀和
        }
        for(int i=n;i>0;--i) {
            scanf("%d",a+n-i+1);
            suffix[i]=suffix[i+1]+v[i];//计算v的后缀和
        }

        int il=1,ir=n;
        while(il<=n) {//寻找对称点
            while(ir>0&&prefix[il]>suffix[ir])
                --ir;
            opp[il]=(prefix[il]==suffix[ir]?ir:0);
            ++il;
        }
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<=n;++i) {
            if(opp[i]!=0&&i<opp[i]) {//当i点是对称点且两个区间没有相交部分
                dp[i]=a[i]+a[n-opp[i]+1];//初始化dp[i]为区间[1,i]、区间[opp[i],n]合并
                for(int j=1;j<i;++j) {
                    if(opp[j]!=0)
                        dp[i]=min(dp[i],dp[j]+a[i-j]+a[opp[j]-opp[i]]);
                }
            }
        }
        ans=a[n];//初始区间[1,n]全部合成一个数字
        for(int i=1;i<=n;++i)
            if(i<opp[i])//区间[i+1,opp[i]-1]合成一个数字
                ans=min(ans,dp[i]+a[opp[i]-i-1]);
        printf("%I64d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值