码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ4572 : [Scoi2016]围棋

时间:2016-05-02 19:48:36      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:

考虑反面,用状压DP求出不合法的方案数。

设$f[i][j][S][x][y]$表示填到了$(i,j)$,轮廓线上每个位置作为末尾是否完全匹配第一个串的状态为$S$,与第一个串kmp到了$x$,与第二个串kmp到了$y$的方案数。

然后直接转移即可。

时间复杂度$O(nm2^{m-c+1}c^2)$。

 

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

  

BZOJ4572 : [Scoi2016]围棋

标签:

原文地址:http://www.cnblogs.com/clrs97/p/5452790.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!