• BZOJ4572 : [Scoi2016]围棋


    考虑反面,用状压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
    ",ans);
      }
      return 0;
    }
    

      

  • 相关阅读:
    ORACLE数据库——触发器的创建和使用
    Oracle——游标的创建和使用
    Oracle数据库和表的操作
    JavaScript中的this,call,apply使用及区别详解
    jQuery插件开发的五种形态小结
    前端图片上传预览
    location.pathname:返回URL的域名(域名IP)后的部分。
    使用Selectivizr让IE6~8支持CSS3
    respond.js有什么作用?
    截取url参数
  • 原文地址:https://www.cnblogs.com/clrs97/p/5452790.html
Copyright © 2020-2023  润新知