fzyzojP2984 -- 序列变换问题

一个区间缩小变换的问题,并且n<=300

启示我们区间dp

我们考虑最后一定是在原串上扣一些,剩一些

所以不妨前求出[l,r]把[l,r]完全处理成什么样子的方案数

然后再来一遍序列dp,统计答案

(并且发现,每次消除其实是减去k-1个,换句话说,对于l,l+k-1,l+2k-1,消除一次之后,还可以再消除,直到最后剩一个,所以考虑关于mod(k-1)的同余位置)

关于g对f的转移,就是我们考虑[l,r]最后一次是从什么消过来的

关于g自己的转移,考虑最后一部分会消成什么样。(最后一个位置不消掉,就是从f[r][r][0/1]转移过来)

代码:

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=303;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll f[303][303][2],g[303][10][1<<8],h[303];
int a[N];
int c[1<<8],w[1<<8];
int n,k;
int main(){
    rd(n);rd(k);
    for(reg i=1;i<=n;++i) rd(a[i]);
    for(reg i=0;i<(1<<k);++i){
        rd(c[i]);rd(w[i]);
    }
    memset(f,0xcf,sizeof f);
    for(reg i=1;i<=n;++i){
        f[i][i][a[i]]=0;
    }
    for(reg l=n;l>=1;--l){
        for(reg i=l-1;i<=n;++i){
            memset(g[i],0xcf,sizeof g[i]);
        }
        g[l-1][0][0]=0;
        g[l][1][a[l]]=0;
        for(reg r=l;r<=n;++r){
            for(reg i=r;i>l;i-=(k-1)){
                for(reg t=1;t<=k&&t<=i-l+1;++t){
                    for(reg s=0;s<(1<<(t-1));++s){
                        g[r][t][s<<1]=max(g[r][t][s<<1],g[i-1][t-1][s]+f[i][r][0]);
                        g[r][t][s<<1|1]=max(g[r][t][s<<1|1],g[i-1][t-1][s]+f[i][r][1]);
                    }
                }
            }
            if((r-l)%(k-1)==0){
                for(reg s=0;s<(1<<k);++s){
                    f[l][r][c[s]]=max(f[l][r][c[s]],w[s]+g[r][k][s]);
                }
                g[r][1][0]=max(g[r][1][0],f[l][r][0]);
                g[r][1][1]=max(g[r][1][1],f[l][r][1]);
            }
        }
    }
    memset(h,0xcf,sizeof h);
    h[0]=0;
    for(reg i=1;i<=n;++i){
        h[i]=h[i-1];
        for(reg j=i;j>=1;j-=(k-1)){
            h[i]=max(h[i],h[j-1]+f[j][i][0]);
            h[i]=max(h[i],h[j-1]+f[j][i][1]);
        }
    }
    printf("%lld
",h[n]);
    return 0;
}

}
signed main(){
    freopen("3.in","r",stdin);
    freopen("3.out","w",stdout);
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/9 18:19:41
*/

就是考虑“统计消去[l,r]的”,再来一次统计“在原序列上消去”

原文地址:https://www.cnblogs.com/Miracevin/p/10358447.html