标签: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.
#include<stdio.h>
__int64 v[5005],a[5005],pre[5005],dp[5005];
void dfs(int l,int r)//分块,使[l,r]对称
{
int i=l,j=r;
__int64 suml=v[l],sumr=v[r];
while(i<j)
{
if(suml==sumr)
{
if(i+1<=j-1)dfs(i+1,j-1);
pre[l]=i; pre[j]=r;//区间最左最右块和相等
return ;
}
if(suml<sumr)suml+=v[++i];
else sumr+=v[--j];
}
pre[l]=r;//一个区间只能合成一块
}
void count(int k)//分成k个块后,从最中间块向两边扩大范围进行DP,pre[i]表示从第一块到
{
int l, r,m;
if(k%2)
{
l=k/2; r=k/2+2; m=k/2+1;//m是最中间块
dp[m]=a[pre[m]-pre[m-1]];
}
else
{
l=k/2; r=k/2+1; m=l; dp[l]=0;
}
while(r<=k)
{
dp[r]=a[pre[r]-pre[l-1]];//合成一大块时
for(int tr=r,tl=l;m<tr;tr--,tl++)//在区间块找出对应的最小dp[r]
if(dp[r]>dp[tr-1]+a[pre[r]-pre[tr-1]]+a[pre[tl]-pre[l-1]])
dp[r]=dp[tr-1]+a[pre[r]-pre[tr-1]]+a[pre[tl]-pre[l-1]];
l--;r++;//向两边扩增
}
}
int main()
{
int n,i,k;
__int64 tk;
while(scanf("%d",&n)>0&&n)
{
for( i=1;i<=n;i++)scanf("%I64d",&v[i]);
for( i=1;i<=n;i++)scanf("%I64d",&a[i]);
dfs(1,n);
k=0; i=1;pre[0]=0;
while(i<=n)//把一整块缩成一个点,pre[k]变成前k个块共有多少个数组成k块
{
tk=pre[i]-i+1; i=pre[i]+1; ++k; pre[k]=tk+pre[k-1];
}
count(k);
printf("%I64d\n",dp[k]);
}
}
HDU4960Another OCD Patient(区间dp,分块后再DP),布布扣,bubuko.com
HDU4960Another OCD Patient(区间dp,分块后再DP)
标签:dp
原文地址:http://blog.csdn.net/u010372095/article/details/38716047