记录编号 438154 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [HAOI 2016]字符合并 最终得分 100
用户昵称 GravatarHZOI_蒟蒻一只 是否通过 通过
代码语言 C++ 运行时间 1.417 s
提交时间 2017-08-15 15:24:06 内存使用 5.01 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=305,maxa=1<<9;
long long f[maxn][maxn][2],c[maxn],v[maxn],a[maxn],g[maxn][maxa],now,tmp[3],ans[maxn];
/*我们这里的f数组与其他的f数组并不完全相同,这里的f数组第三;严格地讲只是半维,0/1表示这个串全部变为0/1可以获得的最大积分,
相应的g数组第二维从半维变成整维,第二维代替了f数组本应该存在的存储最近8位状态的第三维,g数组也就改变了意义,g[i][j]变为转移到i这个长度,状态为j下最大收益;
然后,这个tmp数组中的tmp[i]也就表示了所有可以转化到i的01串转化后连带前面的串可以获得的最大收益。*/
int N,K;
int haha()
{
    freopen("merge_2016.in","r",stdin);
    freopen("merge_2016.out","w",stdout);
    scanf("%d%d",&N,&K);//输入
    int att=(1<<K);//确定最大状态
    memset(f,-1,sizeof(f));//初始化记忆化表格
    for(int i=1;i<=N;i++)//输入01串
    {
        scanf("%1d",&a[i]);
        f[i][i][a[i]]=0;//已经合适,就不需要修改
    }
    for(int i=0;i<att;i++)scanf("%d%d",&c[i],&v[i]);//每一种修改的情况
    for(int i=N-K+1;i>=1;i--)//可以搞这么多轮,从后往前合并
    {
        memset(g,-1,sizeof(g));//初始化
        now=1;g[i][0]=f[i][i][0];g[i][1]=f[i][i][1];//从i开始的串最后一位状态为0、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+=K-1)//每k个为一段判断
                    {
                        if(f[j][k][0]>=0)g[k][s<<1]=max(g[k][s<<1],g[j-1][s]+f[j][k][0]);//可以合成0就合成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]);//可以合成1就合成1,其实这里就是一个区间dp
                    }
            if(++now==K)//长度够了
            {
                tmp[0]=tmp[1]=-1;//初始化转化到尾巴的情况
                for(int k=0;k<(1<<now);k++)
                    if(g[j][k]>=0)tmp[c[k]]=max(tmp[c[k]],v[k]+g[j][k]);//这个状态是可以构建出来的,就更新以目标字符结尾的结果
                f[i][j][1]=g[j][1]=tmp[1];//更新结果
                f[i][j][0]=g[j][0]=tmp[0];
                now=1;
            }
        }
    }
    for(int i=1;i<=N;i++)
        for(int j=i;j<=N;j+=K-1)ans[j]=max(ans[j],ans[i-1]+max(f[i][j][1],f[i][j][0]));//每一个都可以合并,能合就合
    printf("%lld\n",ans[N]);
}
int sb=haha();
int main(){;}