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 ",ans); 46 } 47 }