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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值