BZOJ3864 : Hero meet devil
考虑计算LCS的DP过程,设f[i][j]表示T串的前i项与S串的前j项的LCS,则
若T[i]==S[j],则f[i][j]=f[i-1][j-1]+1
否则f[i][j]=max(f[i-1][j],f[i][j-1])
对于固定的i,f[i][j]只可能为f[i][j-1]或f[i][j-1]+1,把这个差值用二进制表示成状态。
先预处理出每个状态后面加了一个字符后会到达什么状态,然后进行状压DP即可。
时间复杂度$O(m2^n)$。
#include<cstdio> #include<cstring> const int N=15,P=1000000007; int T,n,m,i,j,k,x,a[N+1],f[N+1],g[N+1],v[1<<N][4],F[2][1<<N],ans[N+1];char s[N+1]; inline void up(int&a,int b){a+=b;if(a>=P)a-=P;} void work(){ scanf("%s%d",s+1,&m);n=std::strlen(s+1); for(i=1;i<=n;i++){ if(s[i]=='A')a[i]=0; if(s[i]=='G')a[i]=1; if(s[i]=='T')a[i]=2; if(s[i]=='C')a[i]=3; } for(i=0;i<1<<n;i++){ for(j=0;j<n;j++)f[j+1]=f[j]+(i>>j&1); for(j=0;j<4;j++){ for(k=1;k<=n;k++)if(a[k]==j)g[k]=f[k-1]+1;else g[k]=f[k]>g[k-1]?f[k]:g[k-1]; for(v[i][j]=0,k=1;k<=n;k++)if(g[k]>g[k-1])v[i][j]|=1<<(k-1); } } for(j=0;j<1<<n;j++)F[0][j]=0; for(F[0][0]=1,i=x=0;i<m;i++,x^=1){ for(j=0;j<1<<n;j++)F[x^1][j]=0; for(j=0;j<1<<n;j++)if(F[x][j])for(k=0;k<4;k++)up(F[x^1][v[j][k]],F[x][j]); } for(i=0;i<=n;i++)ans[i]=0; for(i=0;i<1<<n;i++)up(ans[__builtin_popcount(i)],F[x][i]); for(i=0;i<=n;i++)printf("%d\n",ans[i]); } int main(){ for(scanf("%d",&T);T--;work()); return 0; }