令
fi,j,k
表示区间
[i,j]
合并成
k
的最大收益,其中
转移的时候用
gj,k
表示对于当前的
i
,
然后转移一下就行了
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=305;
int n,m;
int a[N],c[N],w[N];
long long f[N][N][2],g[N][N],tmp[2],ans[N];
char s[N];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
int main()
{
n=read(); m=read();
memset(f,-1,sizeof(f));
scanf("%s",s+1);
for (int i=1;i<=n;i++) f[i][i][s[i]-'0']=0;
for (int i=0;i<1<<m;i++)
c[i]=read(),w[i]=read();
for (int i=n-m+1;i;i--)
{
memset(g,-1,sizeof(g));
int now=1;
g[i][0]=f[i][i][0];
g[i][1]=f[i][i][1];
for (int j=i+1;j<=n;j++)
{
for (int s=0;s<1<<now;s++)
if (g[j-1][s]>=0)
for (int k=j;k<=n;k+=m-1)
{
if (f[j][k][0]>=0)
g[k][s<<1]=max(g[k][s<<1],g[j-1][s]+f[j][k][0]);
if (f[j][k][1]>=0)
g[k][s<<1|1]=max(g[k][s<<1|1],g[j-1][s]+f[j][k][1]);
}
if (++now==m)
{
memset(tmp,-1,sizeof(tmp));
for (int s=0;s<1<<m;s++)
if (g[j][s]>=0)
tmp[c[s]]=max(tmp[c[s]],w[s]+g[j][s]);
f[i][j][0]=g[j][0]=tmp[0];
f[i][j][1]=g[j][1]=tmp[1];
now=1;
}
}
}
for (int i=1;i<=n;i++)
for (int j=i;j<=n;j+=m-1)
ans[j]=max(ans[j],ans[i-1]+max(f[i][j][0],f[i][j][1]));
cout << ans[n] << endl;
return 0;
}