• 【HAOI2016】字符合并


    题面

    https://www.luogu.org/problem/P3736

    题解

    首先,要是长度$>=k$,合并了肯定比不合并更优。

    进一步的,区间$[l..r]$的字符,合并的长度是确定的,为$(r-l)\%(m-1)+1$。

    可以设$f[l][r][v]$为区间$[l..r]$的字符,变成$v$的最大分数。不能舍去。

    转移分两种,一种是拼,一种是变化。

    处理拼的转移不需要枚举,直接钦定左区间构成了前$len-1$个字符,右区间构成了最后$1$个字符即可。

    处理变化的情况正如我思考的一样,只需要在$len=1$的情况下枚举是哪一种$01$串构成的即可,然后再变成拼的情况。

    说实话,这样钦定状态优化转移的技巧(类似于搜索中规定转移类型,规定转移顺序)是我所欠缺的,窝什么时候才能像$mbox{Gloid}$爷一样思路顺畅的写出这样优美的$dp$啊。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define ri register int
    #define N 305
    #define LL long long
    using namespace std;
    
    int a[N];
    int n,k;
    LL f[N][N][1<<8];
    int to[1<<8],w[1<<8];
    
    int main() {
      cin>>n>>k;
      for (ri i=1;i<=n;i++) cin>>a[i];
        for (ri i=0;i<(1<<k);i++) cin>>to[i]>>w[i];
        memset(f,-0x3f,sizeof(f));
        for (ri i=1;i<=n;i++) f[i][i][a[i]]=0;
        for (ri len=1;len<n;len++)
            for (ri l=1;l+len<=n;l++) {
              int r=l+len;
                int L=len%(k-1)+1;
                for (ri d=r-1;d>=l;d-=(k-1)) {
                    if (L==1) {
                        for (ri i=0;i<(1<<k);i++) f[l][r][to[i]]=max(f[l][r][to[i]],f[l][d][i>>1]+f[d+1][r][i&1]+w[i]);
                    }
                    else {
                        for (ri i=0;i<(1<<L);i++) f[l][r][i]=max(f[l][r][i],f[l][d][i>>1]+f[d+1][r][i&1]);
                    }
                }
            }
        int ret=0;
        for (ri i=0;i<(1<<k);i++) if (f[1][n][i]>ret) ret=f[1][n][i];
        cout<<ret<<endl;
        return 0;
    }
  • 相关阅读:
    新博客即将启用
    关于博主 | 联系博主
    结束吧,为这不圆满的故事划上一个残缺的句号
    自用线段树模板
    NOIP 2017 day 1 游记
    NOIP 2017 Day 0. 游记
    NOIP 2017 day -1 杂记
    再一次想不出应该起什么标题
    做图与树做到吐的一天
    自用二分图匹配模板
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11799004.html
Copyright © 2020-2023  润新知