HDU 4960:Another OCD Patient

HDU 4960:Another OCD Patient

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4960

题目大意:有$n$个数$v_i$,现要求将相邻的一些数合并使得合并后为回文数列,将$k$个数合并需要代价$a[k]$,一个数只能被合并一次,问最小代价。

分治+记忆化

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define N 5005
 5 using namespace std;
 6 typedef long long ll;
 7 const ll inf=1000000000000000;
 8 ll n,v[N],a[N],pre[N],ans,l,r,dp[N];
 9 ll solve(ll l,ll r){
10     if(l<1||r>n)return inf;
11     if(dp[l]!=-1)return dp[l];
12     ll lt=l--,rt=r++;
13     dp[lt]=a[lt]+a[n-rt+1];
14     while(1<=l&&r<=n){
15         ll L=pre[l],R=pre[n]-pre[r-1];
16         if(L==R){
17             dp[lt]=min(dp[lt],a[lt-l]+a[r-rt]+solve(l,r));
18             l--;
19         }else if(L>R){
20             l--;
21         }else r++;
22     }
23     return dp[lt];
24 }
25 int main(void){
26     while(~scanf("%lld",&n)){
27         if(n==0)break;
28         memset(dp,-1,sizeof(dp));
29         for(int i=1;i<=n;++i){
30             scanf("%lld",&v[i]);
31             pre[i]=pre[i-1]+v[i];
32         }
33         for(int i=1;i<=n;++i)
34             scanf("%lld",&a[i]);
35         ans=a[n],l=1,r=n;
36         while(l<r){
37             ll L=pre[l],R=pre[n]-pre[r-1];
38             if(L==R){
39                 ans=min(ans,solve(l,r)+a[r-l-1]);
40                 l++;
41             }else if(L<R){
42                 l++;
43             }else r--;
44         }
45         printf("%lld\n",ans);
46     }
47 }

 

posted @ 2017-05-16 22:14  barriery  阅读(224)  评论(0编辑  收藏  举报