思路

可能是个套路题,但是没见过...
第一眼觉得是个区间,但是中间的状态总是弄不清楚...
然后看了题解是状压+区间.
表示为区间合并成字符串所获得的最大代价.
区间的划分有个优化就是,每次只能是这种才能形成,然后就行划分,当区间是这个长度的时候进行一次答案统计即可.

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e2+5,M=(1<<8);
char s[N];
ll w[M],c[M],g[2];
ll f[N][N][M];//从l到r合并成v的最大价值是多少.
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    scanf("%s",s+1);
    for(int i=0;i<(1<<k);i++)
        scanf("%lld%lld",&c[i],&w[i]);
    memset(f,-0x3f,sizeof f);
    ll inf=-(0x3f3f3f3f);
    for(int i=1;i<=n;i++)   f[i][i][s[i]-'0']=0;
    for(int len=2;len<=n;len++)
    {
        for(int l=1;l<=n-len+1;l++)
        {
            int r=l+len-1;
            int x=(len-1)%(k-1);
            if(x==0)    x=k-1;
            for(int mid=r-1;mid>=l;mid-=(k-1))
            {
                for(int s=0;s<(1<<x);s++)
                {
                    f[l][r][s<<1]=max(f[l][r][s<<1],f[l][mid][s]+f[mid+1][r][0]);
                    f[l][r][s<<1|1]=max(f[l][r][s<<1|1],f[l][mid][s]+f[mid+1][r][1]);
                }
            }
            if(x==k-1)
            {
                g[0]=g[1]=inf;
                for(int i=0;i<(1<<k);i++)   g[c[i]]=max(g[c[i]],f[l][r][i]+w[i]);
                f[l][r][0]=g[0],f[l][r][1]=g[1];
            }
        }
    }
    ll ans=inf;
    for(int i=0;i<(1<<k);i++)
        ans=max(ans,f[1][n][i]);
    printf("%lld\n",ans);
    return 0;
}