题目大意
有个n*m的格子图,每个格子上有三种数。
给出q个2*c模版,对于每个模版,求有多少种格子图能够匹配这个模版。
数据范围
q
≤
5
直观想法
设
fi,s
表示现在匹配到第i行,第i行的状态为s(s为三进制数)的方案数。
转移显然。
然后这样的时间复杂度是
O(n×32m)
超时,估计只有20分。
缩减状态
每次计算匹配一个的。
可以发现,由于我们只要匹配一个模版,所以有许多的状态都是无用的,于是我们可以缩减状态。
如何缩减?
对于一个状态,我们关心的只是那个位置匹配了
s0
(或
s1
,注:
s0
表示模板的第一行,
s1
表示模版的第二行,以下都这样简称),那么对于每个确定的串,它是有两个二进制状态的,一个二进制位为1当且仅当以当前位为结尾的c为是与模版是一样的,举个例子:
然后由于前c-1位都不可能为1(因为一个二进制位为1当且仅当以当前位为结尾的c为是与模版是一样的),所以共有
2m−c+1
种状态。
那么转移的东西如图(箭头表示由哪个数组推出哪个数组,可能本人比较蠢,用的数组太多了):
转移就很显然了,额如果不明白,看标称吧^_^
这样的时间复杂度就是
O(n×22m−2c+2)
空间复杂度为
O(m×c2×22m−2c+2)
然后,如果m-c比较大,它就会GG了
很遗憾,数据中真的有这样的数据。。。。。
庆幸的是,数据中的这个的n是等于2的,n=2又可以怎样做呢,于是他就可以直接dp就好了,设u[i][w0][w1]表示当前做到第i位,匹配到s0的w0,s1的w1,然后转移显然。。。。。
感觉很水的方法啊啊啊啊啊
说一句:有种水法的感觉
贴个代码哈哈哈哈哈哈:
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
typedef double db;
int get(){
char ch;
int s=0;
bool pd=0;
while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');
if (ch=='-')pd=1;
else s=ch-'0';
while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
if (pd)return -s;
return s;
}
const int N = 110;
const int M = 20;
const int mo = 1e+9+7;
const int zt = 260;
int mi[13],n,m,c,q,len;
int t[M][7][7][zt][zt],g[zt][zt],p[zt],v[zt][zt],w[zt],f[N][zt];
int u[N][7][7];
LL ans;
int s[2][M];
int next[2][M];
LL v3[N*M];
int trans(char ch){
switch (ch){
case 'W':return 0;
case 'B':return 1;
case 'X':return 2;
}
}
void init(int v){
char ch;
while(ch=getchar(),ch!='B'&&ch!='W'&&ch!='X');
s[v][1]=trans(ch);
fo(i,2,c)s[v][i]=trans(getchar());
int j=0;
fo(i,2,c){
while(j&&s[v][j+1]!=s[v][i])j=next[v][j];
if (s[v][j+1]==s[v][i])j++;
next[v][i]=j;
}
}
void work0(){
fo(ttt,1,q){
init(0);
init(1);
fo(i,0,m)fo(w0,0,c)fo(w1,0,c)u[i][w0][w1]=0;
u[0][0][0]=1;
ans=0;
fo(i,0,m-1)
fo(w0,0,c-1)
fo(w1,0,c-1)
if (u[i][w0][w1]){
fo(v0,0,2)
fo(v1,0,2){
int _w0=w0,_w1=w1;
while(_w0&&s[0][_w0+1]!=v0)_w0=next[0][_w0];
if (s[0][_w0+1]==v0)_w0++;
while(_w1&&s[1][_w1+1]!=v1)_w1=next[1][_w1];
if (s[1][_w1+1]==v1)_w1++;
if (_w0==c&&_w1==c)
ans=(ans+LL(u[i][w0][w1])*v3[2*(m-1-i)]%mo)%mo;
else{
if (_w0==c)_w0=next[0][c];
if (_w1==c)_w1=next[1][c];
u[i+1][_w0][_w1]=(u[i+1][_w0][_w1]+u[i][w0][w1])%mo;
}
}
}
printf("%lld\n",ans);
}
}
void work1(){
fo(ttt,1,q){
init(0);
init(1);
fo(i,0,m)fo(w0,0,c)fo(w1,0,c)fo(t0,0,mi[len]-1)fo(t1,0,mi[len]-1)
t[i][w0][w1][t0][t1]=0;
fo(t0,0,mi[len]-1)fo(t1,0,mi[len]-1)g[t0][t1]=v[t0][t1]=0;
fo(t0,0,mi[len]-1)p[t0]=w[t0]=0;
fo(i,0,n)fo(t0,0,mi[len]-1)f[i][t0]=0;
t[0][0][0][0][0]=1;
fo(i,0,m-1)
fo(w0,0,c-1)
fo(w1,0,c-1)
fo(t0,0,mi[len]-1)
fo(t1,0,mi[len]-1)
if (t[i][w0][w1][t0][t1]){
fo(v,0,2){
int _w0=w0,_w1=w1,_t0=t0,_t1=t1;
while(_w0&&s[0][_w0+1]!=v)_w0=next[0][_w0];
if (s[0][_w0+1]==v)_w0++;
while(_w1&&s[1][_w1+1]!=v)_w1=next[1][_w1];
if (s[1][_w1+1]==v)_w1++;
if (_w0==c){
_w0=next[0][c];
_t0|=mi[i+1-c];
}
if (_w1==c){
_w1=next[1][c];
_t1|=mi[i+1-c];
}
t[i+1][_w0][_w1][_t0][_t1]=(t[i+1][_w0][_w1][_t0][_t1]+t[i][w0][w1][t0][t1])%mo;
}
}
fo(w0,0,c-1)
fo(w1,0,c-1)
fo(t0,0,mi[len]-1)
fo(t1,0,mi[len]-1){
g[t0][t1]=(g[t0][t1]+t[m][w0][w1][t0][t1])%mo;
p[t1]=(p[t1]+t[m][w0][w1][t0][t1])%mo;
}
fo(t0,0,mi[len]-1)
fo(t1,0,mi[len]-1)
if ((t1&t0)>0)w[t0]=(w[t0]+p[t1])%mo;
else
fo(_t0,0,mi[len]-1)
v[t0][_t0]=(v[t0][_t0]+g[t1][_t0])%mo;
f[0][0]=1;
ans=0;
fo(i,0,n-1)
fo(t0,0,mi[len]-1)
if (f[i][t0]){
ans=(ans+LL(f[i][t0])*w[t0]%mo*v3[(n-i-1)*m]%mo)%mo;
fo(_t0,0,mi[len]-1)
f[i+1][_t0]=(f[i+1][_t0]+LL(f[i][t0])*v[t0][_t0]%mo)%mo;
}
printf("%lld\n",ans);
}
}
int main(){
n=get();m=get();c=get();q=get();
v3[0]=1;
fo(i,1,n*m)v3[i]=v3[i-1]*3%mo;
mi[0]=1;
fo(i,1,12)mi[i]=mi[i-1]*2;
len=m-c+1;
if (n==2)work0();
else work1();
return 0;
}