【BZOJ】4572: [Scoi2016]围棋-轮廓线DP

版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82710601

传送门:bzoj4572


题解

算可以匹配的比较麻烦,转化成求不能匹配的,取个补集即可。

c 6 , m 12 ,数据范围明示轮廓线DP,设 f [ k ] [ s t a ] [ i ] [ j ] ( 0 k n , 0 s t a < 2 m c + 1 , 0 i , j < c ) 表示当前处理到第 k 排, s t a 二进制第 q 位上0/1表示轮廓线上第 q 列的位置是否能匹配到模板第一排末尾位置。

容我贴波图,来源:hsfzLZH1-洛谷博客
这里写图片描述

假设 ( x , y ) 位于第 x 行,已经处理到了第 y 列,轮廓线就是红色标记的一行。

询问时先预处理出kmp转移,第一维可以滚动数组,然后直接DP即可。时间复杂度 O ( Q ( 7 c + 3 n m 2 m c 2 ) ) (粗略算了一下)


代码

#include<bits/stdc++.h>
#define RI register
using namespace std;
const int mod=1e9+7,N=(1<<12)+10;

int n,m,c,Q,bin[15],col[10],f[2][N][7][7];
int nxt[2][10],to[2][10][3],tp,mxx,ori,ans;
char s[10];

inline void ad(int &x,int y){x+=y;x-= x>=mod? mod:0;}
inline void dc(int &x,int y){x-=y;x+= x<0? mod:0;}
inline int mul(int x,int y){return 1ll*x*y%mod;}

inline int fp(int x,int y)
{
    int re=1;
    for(;y;y>>=1,x=mul(x,x))
     if(y&1) re=mul(re,x);
    return re; 
}

inline void trans()
{
    scanf("%s",s+1);
    for(RI int i=1;i<=c;++i){
        if(s[i]=='W') col[i]=0;
        else if(s[i]=='B') col[i]=1;
        else col[i]=2;
    }
}

int main(){
    RI int i,j,k,t,s,x,y,a,b,res,kmp;
    bin[0]=1;for(i=1;i<=12;++i) bin[i]=bin[i-1]<<1;
    scanf("%d%d%d%d",&n,&m,&c,&Q);
    mxx=bin[m-c+1];ori=fp(3,n*m);
    for(;Q;--Q){
        tp=0;
        for(i=0;i<2;++i){
            trans();
            for(kmp=0,j=2;j<=c;++j){
                for(;kmp && col[kmp+1]!=col[j];kmp=nxt[i][kmp]);
                kmp+= col[kmp+1]==col[j];
                nxt[i][j]=kmp;
            }
            for(j=0;j<c;++j){
                for(k=0;k<3;++k){
                    for(t=j;t && col[t+1]!=k;t=nxt[i][t]);
                    t+= col[t+1]==k;
                    to[i][j][k]=t;
                }
            }
        }
        memset(f[1],0,sizeof(f[1]));
        f[1][0][0][0]=1;
        for(i=1;i<=n;++i){
            memset(f[tp],0,sizeof(f[tp]));
            for(s=0;s<mxx;++s)
             for(x=0;x<c;++x)
              for(y=0;y<c;++y)
               ad(f[tp][s][0][0],f[tp^1][s][x][y]);
            for(tp^=1,j=1;j<=m;++j,tp^=1){
                memset(f[tp],0,sizeof(f[tp]));
                for(s=0;s<mxx;++s)
                 for(x=0;x<c;++x)
                  for(y=0;y<c;++y) 
                   if(f[tp^1][s][x][y])
                    for(k=0;k<3;++k){
                        a=to[0][x][k],b=to[1][y][k];res=s;
                        if(j>=c && (s&bin[j-c])) res^=bin[j-c];
                        if(a==c) {res^=bin[j-c];a=nxt[0][a];}
                        if(b==c) {if(s&bin[j-c]) continue;b=nxt[1][b];}
                        ad(f[tp][res][a][b],f[tp^1][s][x][y]);
                    }
            }
        } 
        tp^=1;ans=ori;
        for(s=0;s<mxx;++s) 
          for(x=0;x<c;++x)
           for(y=0;y<c;++y)
              dc(ans,f[tp][s][x][y]);
         printf("%d\n",ans);
    }
} 

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/82710601
今日推荐