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

如果k==2的话就是记搜,

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

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

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

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

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

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

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


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

#include<iostream>
#include<cstdio> 
using namespace std;
#define N 305
int a[N],n,K,i,j,k,l,mb[N];
long long er[N],f[N][N][N],v[N],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);
}


猜你喜欢

转载自blog.csdn.net/haobang866/article/details/79221690