BZOJ 4565 状压DP

思路:

f[i][j][S]表示从i到j压成S状态

j-m是k-1的倍数

$f[i][j][S<<1]=max(f[i][j][S<<1],f[i][m-1][S]+f[m][j][0]),$
$f[i][j][S<<1|1]=max(f[i][j][S<<1|1],f[i][m-1][S]+f[m][j][1]);$


为了区分001 01 和1

更新的时候要新开一个数组记录 最后再更新

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
int n,k,f[333][333][256],g[2],ans,c[333],w[333];
char s[333];
signed main(){
    scanf("%lld%lld",&n,&k);
    scanf("%s",s+1);
    for(int i=0;i<(1<<k);i++)scanf("%lld%lld",&c[i],&w[i]);
    memset(f,0xcf,sizeof(f));
    for(int i=1;i<=n;i++)s[i]-='0',f[i][i][s[i]]=0;
    for(int l=2;l<=n;l++)
        for(int i=1;i<=n-l+1;i++){
            int j=i+l-1,len=j-i;
            while(len>=k)len-=k-1;
            for(int m=j;m>i;m-=k-1)
                for(int S=0;S<(1<<len);S++)
                    f[i][j][S<<1]=max(f[i][j][S<<1],f[i][m-1][S]+f[m][j][0]),
                    f[i][j][S<<1|1]=max(f[i][j][S<<1|1],f[i][m-1][S]+f[m][j][1]);
            if(len==k-1){
                g[0]=g[1]=-100000000000000ll;
                for(int S=0;S<(1<<k);S++)
                    g[c[S]]=max(g[c[S]],f[i][j][S]+w[S]);
                f[i][j][0]=g[0],f[i][j][1]=g[1];
            }
        }
    for(int i=0;i<(1<<k);i++)ans=max(ans,f[1][n][i]);
    printf("%lld
",ans);
}
原文地址:https://www.cnblogs.com/SiriusRen/p/6654390.html