BZOJ3864 : Hero meet devil

Claris發表於2015-09-10

考慮計算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;
}

  

相關文章