传送门:bzoj4572
题解
算可以匹配的比较麻烦,转化成求不能匹配的,取个补集即可。
c≤6,m≤12 c ≤ 6 , m ≤ 12 ,数据范围明示轮廓线DP,设 f[k][sta][i][j](0≤k≤n,0≤sta<2m−c+1,0≤i,j<c) f [ k ] [ s t a ] [ i ] [ j ] ( 0 ≤ k ≤ n , 0 ≤ s t a < 2 m − c + 1 , 0 ≤ i , j < c ) 表示当前处理到第 k k 排,二进制第 q q 位上0/1表示轮廓线上第列的位置是否能匹配到模板第一排末尾位置。
容我贴波图,来源:hsfzLZH1-洛谷博客
假设 (x,y) ( x , y ) 位于第 x x 行,已经处理到了第列,轮廓线就是红色标记的一行。
询问时先预处理出kmp转移,第一维可以滚动数组,然后直接DP即可。时间复杂度
O(Q(7c+3nm2mc2))
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);
}
}