BZOJ4572 : [Scoi2016]圍棋

考慮反面,用狀壓DP求出不合法的方案數。blog

設$f[i][j][S][x][y]$表示填到了$(i,j)$,輪廓線上每一個位置做爲末尾是否徹底匹配第一個串的狀態爲$S$,與第一個串kmp到了$x$,與第二個串kmp到了$y$的方案數。io

而後直接轉移便可。class

時間複雜度$O(nm2^{m-c+1}c^2)$。di

 

#include<cstdio>
const int P=1000000007;
int T,n,m,c,i,j,k,S,x,y,A,B,nxt[9],ta[9][3],tb[9][3],na,nb,U,E;
int f[1024][6][6],g[1024][6][6],ans;
char a[9],b[9];
inline int id(char x){
  if(x=='B')return 0;
  return x=='W'?1:2;
}
inline void up(int&x,int y){x+=y;if(x>=P)x-=P;}
inline void clear(){for(S=0;S<U;S++)for(x=0;x<c;x++)for(y=0;y<c;y++)g[S][x][y]=0;}
inline void copy(){for(S=0;S<U;S++)for(x=0;x<c;x++)for(y=0;y<c;y++)f[S][x][y]=g[S][x][y];}
int main(){
  scanf("%d%d%d%d",&n,&m,&c,&T);
  while(T--){
    scanf("%s%s",a+1,b+1);
    for(i=1;i<=c;i++)a[i]=id(a[i]),b[i]=id(b[i]);
    for(nxt[1]=j=0,i=2;i<=c;nxt[i++]=j){
      while(j&&a[j+1]!=a[i])j=nxt[j];
      if(a[j+1]==a[i])j++;
    }
    for(na=nxt[c],i=0;i<c;i++)for(j=0;j<3;j++){
      for(k=i;k&&a[k+1]!=j;k=nxt[k]);
      if(a[k+1]==j)k++;
      ta[i][j]=k;
    }
    for(nxt[1]=j=0,i=2;i<=c;nxt[i++]=j){
      while(j&&b[j+1]!=b[i])j=nxt[j];
      if(b[j+1]==b[i])j++;
    }
    for(nb=nxt[c],i=0;i<c;i++)for(j=0;j<3;j++){
      for(k=i;k&&b[k+1]!=j;k=nxt[k]);
      if(b[k+1]==j)k++;
      tb[i][j]=k;
    }
    U=1<<(m-c+1);
    for(S=0;S<U;S++)for(x=0;x<c;x++)for(y=0;y<c;y++)f[S][x][y]=0;
    for(f[0][0][0]=i=1;i<=n;i++){
      clear();
      for(S=0;S<U;S++)for(x=0;x<c;x++)for(y=0;y<c;y++)if(f[S][x][y])up(g[S][0][0],f[S][x][y]);
      copy();
      for(j=1;j<=m;j++){
        clear();
        for(S=0;S<U;S++)for(x=0;x<c;x++)for(y=0;y<c;y++)if(f[S][x][y])for(k=0;k<3;k++){
          E=S;
          if(j>=c)if(S>>(j-c)&1)E^=1<<(j-c);
          A=ta[x][k];
          if(A==c)E|=1<<(j-c),A=na;
          B=tb[y][k];
          if(B==c){
            if(S>>(j-c)&1)continue;
            B=nb;
          }
          up(g[E][A][B],f[S][x][y]);
        }
        copy();
      }
    }
    for(ans=1,i=n*m;i;i--)ans=3LL*ans%P;
    for(S=0;S<U;S++)for(x=0;x<c;x++)for(y=0;y<c;y++)up(ans,P-f[S][x][y]);
    printf("%d\n",ans);
  }
  return 0;
}
相關文章
相關標籤/搜索