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;
}

  

posted @ 2015-09-10 22:45  Claris  阅读(507)  评论(0编辑  收藏