P3290 [SCOI2016] 围棋
题意
定义一个棋盘为一个 \(n\times m\) 的网格,每个格子内有 'W','H','X' 三种字母之一。定义一个模板为一个 \(2\times c\) 的网格,每个格子内有 'W','H','X' 三种字母之一。当一个棋盘内包含模板时,称祂为好的棋盘。对于给出的 \(q\) 种模板,分别求出好的棋盘的总数。
\(n\le100,m\le12,c\le6,q\le5\)。
思路
显然,需要 \(DP\),考虑计算不包含模板的方案数。
先对模板第一行和第二行分别建 \(ACAM\)。
设当前在转移点 \((x,y)\),用一个二进制数记录轮廓线上的状态。\(1\) 表示这个位置和祂向前 \(c\) 个位置能和模板的第一行匹配,\(0\) 表示不能。设 \(f_{x,y,s,w1,w2}\) 表示二进制状态为 \(s\),当前行前面填的字符和模板第一行匹配到 \(w1\) 位,和模板第二行匹配到 \(w2\) 位的方案数。
枚举当前位置填什么字符并进行更新。时间复杂度 \(\mathcal O(qnm2^mc^2)\),实现的不好可能 \(TLE\)。
发现二进制状态的前 \(c-1\) 位一定全是 \(0\),没有意义,可以删掉,复杂度优化为 \(\mathcal O(qnm2^{m-c+1}c^2)\)。
代码
// Problem: P3290 [SCOI2016] 围棋
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3290
// Memory Limit: 512 MB
// Time Limit: 6000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
template<int mod>struct Modint{
int z;
Modint(){z=0;}
Modint(int x){x%=mod;z=x<0?x+mod:x;}
Modint(long long x){x%=mod;z=x<0?x+mod:x;}
Modint(short x){x%=mod;z=x<0?x+mod:x;}
Modint(char x){x%=mod;z=x<0?x+mod:x;}
Modint(bool x){x%=mod;z=x<0?x+mod:x;}
friend Modint operator+(Modint t,Modint t2){Modint ans;ans.z=(t.z+t2.z)%mod;return ans;}
friend Modint operator*(Modint t,Modint t2){Modint ans;ans.z=1ll*t.z*t2.z%mod;return ans;}
friend Modint operator-(Modint t,Modint t2){Modint ans;ans.z=(t.z-t2.z)%mod;return ans;}
Modint operator-()const{return (Modint){-z};}
Modint operator<<(const int t)const{Modint ans;ans.z=(z<<t)%mod;return ans;}
Modint operator>>(const int t)const{Modint ans;ans.z=(z>>t)%mod;return ans;}
Modint&operator+=(const Modint t){z=(z+t.z)%mod;return *this;}
Modint&operator*=(const Modint t){z=1ll*z*t.z%mod;return *this;}
Modint&operator-=(const Modint t){z=(z-t.z)%mod;return *this;}
Modint&operator<<=(const int t){z=(z<<t)%mod;return *this;}
Modint&operator>>=(const int t){z=(z>>t)%mod;return *this;}
Modint&operator++(){z++,z%=mod;return *this;}
Modint&operator--(){z--,z%=mod;return *this;}
Modint operator++(int){Modint ls=*this;z++,z%=mod;return ls;}
Modint operator--(int){Modint ls=*this;z--,z%=mod;return ls;}
friend Modint ksm(Modint a,int b){
Modint ans=1;
while(b){if(b&1) ans=ans*a;a=a*a,b>>=1;}
return ans;
}
friend void read(Modint&z){
int x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=(x*10ll+c-'0')%mod,c=getchar();
f?x=-x:0;
z.z=x;
}
friend void write(Modint x){x.z<0?x.z+=mod:0;write(x.z);}
};
const int mod=1000000007;
#define M Modint<mod>
const int maxn=110,maxc=8;
int n,m,c,q;
M f[2][5000][maxc][maxc];
class ACAM{
private:
struct node{int ch[5],fail,end;}t[maxn];
int cnt;
public:
void clear(){cnt=0;memset(t,0,sizeof(t));}
void insert(vector<int>vt){
int u=0;
for(int i:vt){
if(t[u].ch[i]==0) t[u].ch[i]=++cnt;
u=t[u].ch[i];
}
t[u].end=1;
}
void build(){
queue<int>q;
for(int i=0;i<3;i++) if(t[0].ch[i]) q.push(t[0].ch[i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<3;i++){
if(t[u].ch[i]) t[t[u].ch[i]].fail=t[t[u].fail].ch[i],q.push(t[u].ch[i]),t[t[u].ch[i]].end|=t[t[t[u].ch[i]].fail].end;
else t[u].ch[i]=t[t[u].fail].ch[i];
}
}
}
bool is_end(int u){return t[u].end;}
int nxt(int u,int x){return t[u].ch[x];}
}ac1,ac2;
int get(char x){
if(x=='W') return 0;
if(x=='B') return 1;
return 2;
}
void solve(){
memset(f,0,sizeof(f));
ac1.clear(),ac2.clear();
string s,t;read(s,t);
vector<int>vt,vtt;
for(int i=0;i<c;i++) vt.push_back(get(s[i])),vtt.push_back(get(t[i]));
ac1.insert(vt),ac2.insert(vtt);
ac1.build(),ac2.build();
M ans=0;
int nw=1,lt=0;
f[nw][0][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
swap(nw,lt);
for(int s=0;s<(1<<m-c+1);s++) for(int w1=0;w1<=c;w1++) for(int w2=0;w2<=c;w2++) f[nw][s][w1][w2]=0;
for(int s=0;s<(1<<m-c+1);s++) for(int w1=0;w1<=c;w1++) for(int w2=0;w2<=c;w2++){
for(int ch=0;ch<3;ch++){
int ww1=ac1.nxt(w1,ch),ww2=ac2.nxt(w2,ch),ss=s;
if(j-c>=0){
if((s&(1<<j-1-c+1))&&ac2.is_end(ww2)) continue;
if(ac1.is_end(ww1)) ss|=(1<<j-1-c+1);
else if((s&(1<<j-1-c+1))) ss^=(1<<j-1-c+1);
}
f[nw][ss][ww1][ww2]+=f[lt][s][w1][w2];
}
}
}
for(int s=0;s<(1<<m-c+1);s++) for(int w1=0;w1<=c;w1++) for(int w2=0;w2<=c;w2++) if(w1!=0||w2!=0) f[nw][s][0][0]+=f[nw][s][w1][w2],f[nw][s][w1][w2]=0;
}
for(int s=0;s<(1<<m-c+1);s++) for(int w1=0;w1<=c;w1++) for(int w2=0;w2<=c;w2++) ans+=f[nw][s][w1][w2];
write(ksm(M(3),n*m)-ans);
}
signed main(){
read(n,m,c,q);
while(q--) solve(),write("\n");
return 0;
}

浙公网安备 33010602011771号