4565: [Haoi2016]字符合并 区间DP

来源:互联网 发布:php发送短信验证码 编辑:程序博客网 时间:2024/05/22 07:41

fi,j,k表示区间[i,j]合并成k的最大收益,其中K=0/1保证[i,j]可以合并成一个数。
转移的时候用gj,k表示对于当前的i,[i,j]合并成了k,其中k是一个二进制数。
然后转移一下就行了

#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;}
0 0
原创粉丝点击