一个区间缩小变换的问题,并且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]的”,再来一次统计“在原序列上消去”