您的位置:首页 > 其它

bzoj4565 [HAOI2016]字符合并 结论+状压+区间dp

2018-01-31 20:22 274 查看
如果k==2的话就是记搜,

但这个题用记搜的思路的话是需要枚举k个断点的,

所以对于枚举断点,就很可能有优化,比如到一个断点,一个决策的最优值

于是考虑区间dp模型,相当于是插入一个数,然后看影响。

然后合并显然是从插入点到另一个端点,所以可以从插入点到另一个端点枚举区间

然后插入的点会和左边的点合并,所以可以状压状态,有用的只有k位,大于k的会合并

然后有一个非常非常重要的潜在条件就是区间一定,位数一定;

所以就不用枚举位数区分000001和单独的1

码(注意bzoj版本是连在一起的,其他版本不是,这是其他版本的):

#include<iostream>
#include<cstdio> 
using namespace std;
#define N 305
int a
,n,K,i,j,k,l,mb
;
long long er
,f

,v
,g[5],ans=-999999999999,len;
int main()
{
scanf("%d%d",&n,&K);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
er[0]=1;for(i=1;i<=9;i++)er[i]=er[i-1]*2;
for(i=0;i<er[K];i++)
{
scanf("%d",&mb[i]);
scanf("%lld",&v[i]);
}
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
{
for(k=0;k<er[K];k++)
f[i][j][k]=-999999999999;
}
for(i=1;i<=n;i++)
for(j=i;j>=1;j--)
{
if(i==j){f[i][j][a[i]]=0;continue;}
for(k=i;k>j;k-=(K-1))
{
len=k-j;
while(len>=K)len-=(K-1);
for(l=0;l<er[len];l++)
{
if(f[k][i][1]>=0)f[j][i][l<<1|1]=max(f[j][i][l<<1|1],f[j][k-1][l]+f[k][i][1]);
if(f[k][i][0]>=0)f[j][i][l<<1]=max(f[j][i][l<<1],f[j][k-1][l]+f[k][i][0]);
}
}
    if(K==1||((i-j)%(K-1)==0))//化而为一 
    {
    g[0]=g[1]=-999999999999;
    	for(k=0;k<er[K];k++)
    	{
    		g[mb[k]]=max(g[mb[k]],f[j][i][k]+v[k]);
            f[j][i][k]=-999999999999;
}
    f[j][i][1]=g[1];
f[j][i][0]=g[0];  
}
}
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
{
for(k=0;k<er[K];k++)
ans=max(f[i][j][k],ans);
}
printf("%lld",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: