5336: [TJOI2018]party
题解:
比较水啦。。dp套dp
f[i][j][k]表示枚举了前i位,最大公共子序列匹配状态为j,noi匹配到了第k位
因为g[j]和g[j+1]最多差1 所以可以状压成j
然后内层再dp一下搞出下一个j
于是他的名字就叫做dp套dp了
代码:
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define mid ((h+t)>>1) #define ll long long const int mo=1e9+7; char s[20]; int n,k,f[2][100000][3],c[20],g[20],ans[20]; #define js(x,y) x+y>mo?x=x+y-mo:x=x+y int qu(int x,int y) { int f[20]; f[0]=0; rep(i,0,k-1) if ((x>>i)&1) f[i+1]=f[i]+1; else f[i+1]=f[i]; rep(i,1,k) { g[i]=max(f[i],g[i-1]); g[i]=max(g[i],f[i-1]+(c[i]==y)); } int ans=0; rep(i,1,k) if (g[i]>g[i-1]) ans+=1<<(i-1); return(ans); } int pp(int x) { int cnt=0; while (x) { if (x&1) cnt++; x/=2; } return cnt; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); cin>>n>>k; cin>>s; rep(i,1,k) if (s[i-1]=='N') c[i]=1; else if (s[i-1]=='O') c[i]=2; else c[i]=3; f[0][0][0]=1; rep(i,1,n) { rint now=i%2,lst=(i+1)%2; memset(f[now],0,sizeof(f[now])); rep(i,0,((1<<k)-1)) { if (f[lst][i][0]) { rep(kk,1,3) { int x1=qu(i,kk),x2=0; if (kk==1) x2=1; js(f[now][x1][x2],f[lst][i][0]); } } if (f[lst][i][1]) { rep(kk,1,3) { int x1=qu(i,kk),x2=0; if (kk==2) x2=2; if (kk==1) x2=1; js(f[now][x1][x2],f[lst][i][1]); } } if (f[lst][i][2]) { rep(kk,1,2) { int x1=qu(i,kk),x2=0; if (kk==1) x2=1; js(f[now][x1][x2],f[lst][i][2]); } } } } int kk=n%2; rep(i,0,(1<<k)-1) rep(j,0,2) js(ans[pp(i)],f[kk][i][j]); rep(i,0,k) cout<<ans[i]<<endl; return 0; }