https://www.lydsy.com/JudgeOnline/problem.php?id=5336
萌新第一次写dp套dp.
先不考虑有NOI的限制.
考虑普通lcs是怎么做的.
f[i][j]=max(f[i-1][j],f[i][j-1],(f[i-1][j-1]+1)*[S[i]==T[j]]).
设f[i]表示对于原串,生出串做到第i的位置时,最长公共子序列长度.
发现相邻的i-1~i只会f值最多+1,于是可以对这个状态进行差分后,状压存储.
预处理出在状态S后添加字符w[i],所得到的新的f[].
设dp[i][S][len]表示dp到第i位,f的差分后状态位S,匹配NOI字符串的长度为len.
添加字符w有
dp[i][trans[S][w]][mp[len][w]]+=dp[i-1][S][len].
#include<cstdio> #include<algorithm> #include<cstring> #define rep(i,s,t) for(register int i=s;i<=t;++i) #define _rep(i,s,t) for(register int i=s;i>=t;--i) #define Rep(i,s,t) for(register int i=s;i<t;++i) #define go(x) for(register int e=las[x];e;e=nxt[e]) #define re register #define fi first #define se second #define mp(x,y) make_pair(x,y) #define pb push_back #define pii pair<int,int> #define gi(x) read(x) #define gii(x,y) read(x),read(y) #define giii(x,y,z) read(x),read(y),read(z) #define ms(f,x) memset(f,x,sizeof f) namespace IO{ #define gc getchar() #define pc(x) putchar(x) template<typename T>inline void read(T &x){ x=0;int f=1;char ch=gc;while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=gc;} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;x*=f;return; } template<typename T>inline void write(T x=0){ T wr[51];wr[0]=0;if(x<0)pc('-'),x=-x;if(!x)pc(48); while(x)wr[++wr[0]]=x%10,x/=10;while(wr[0])pc(48+wr[wr[0]--]);return; } } using IO::read; using IO::write; typedef long long ll; typedef double db; using namespace std; const int mod=1e9+7; char w[]={'N','O','I'}; char ch[20]; int n,m,S; int f[2][1<<15][3],mp[3][3],ans[1011]; int g[20],h[20],trans[1<<15][3],sz[1<<15]; inline void inc(int &x,int y){ x+=y; if(x>=mod)x-=mod; } inline int zip(int *h){ re int s=0; rep(i,1,n) s|=((h[i]-h[i-1])<<(i-1)); return s; } inline void unzip(int *h,int s){ rep(i,1,n) h[i]=h[i-1]+(s&1),s>>=1; } inline void init(){ rep(i,1,S)sz[i]=sz[i>>1]+(i&1); rep(k,0,2)rep(s,0,S){ unzip(g,s),ms(h,0); rep(i,1,n){ h[i]=max(h[i-1],g[i]); if(w[k]==ch[i]) h[i]=max(h[i],g[i-1]+1); } trans[s][k]=zip(h); } } int main(){ gii(m,n),scanf("%s",ch+1),S=(1<<n)-1,init(); mp[0][0]=mp[1][0]=mp[2][0]=f[0][0][0]=1,mp[1][1]=2; rep(i,1,m){ int p=i&1,q=p^1; ms(f[p],0); rep(s,0,S)rep(j,0,2)rep(k,0,2){ if(k==2&&j==2)continue; re int y=trans[s][k]; inc(f[p][y][mp[j][k]],f[q][s][j]); } } rep(s,0,S)rep(j,0,2) inc(ans[sz[s]],f[m&1][s][j]); rep(i,0,n) printf("%d ",ans[i]); return 0; }