【LOJ #2017】「SCOI2016」圍棋—(輪廓線dp+KMP)

傳送門

考慮計算完全沒有的情況減去

f[i][j][sta][k][p]f[i][j][sta][k][p]
表示到i,ji,j當前這行和上面一行與模式串第一行匹配的狀態爲stasta
上一行和第一行模式串匹配到了kk,第二行匹配到了jj
stasta是由於上面一行和當前這行總共有用的位置只有mc+1m-c+1
所以用輪廓線壓起來

然後預處理模式串每個位置加一個字符匹配到的位置
隨便亂搞搞dpdp就可以了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=(1<<20)|5;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define pb push_back
#define re register
#define fi first
#define se second
#define pii pair<int,int>
#define cs const
#define bg begin
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Add(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline void Mul(int &a,int b){a=1ll*a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int N=15,M=(1<<13)|5;
int f[2][M][N][N];
int nxta[N][3],nxtb[N][3],nxt[N];
int n,m,c,q,a[N],eda,edb,lim,now;
char s[N];
inline int get(char x){
	if(x=='W')return 0;
	if(x=='B')return 1;
	if(x=='X')return 2;
}
inline void clear(){
	for(int i=0;i<lim;i++)
	for(int x=0;x<c;x++)
	for(int y=0;y<c;y++)f[now][i][x][y]=0;
}
int main(){
	#ifdef Stargazer
	freopen("lx.cpp","r",stdin);
	#endif
	n=read(),m=read(),c=read(),q=read();
	while(q--){
		scanf("%s",s+1);
		for(int i=1;i<=c;i++)a[i]=get(s[i]);
		for(int i=0,j=2;j<=c;j++){
			while(i&&a[i+1]!=a[j])i=nxt[i];
			if(a[i+1]==a[j])i++;
			nxt[j]=i;
		}
		eda=nxt[c];
		for(int i=0;i<=c;i++){
			for(int k=0;k<=2;k++){
				int p=i;
				while(p&&a[p+1]!=k)p=nxt[p];
				if(a[p+1]==k)p++;
				nxta[i][k]=p;
			}
		}
		scanf("%s",s+1);
		for(int i=1;i<=c;i++)a[i]=get(s[i]);
		for(int i=0,j=2;j<=c;j++){
			while(i&&a[i+1]!=a[j])i=nxt[i];
			if(a[i+1]==a[j])i++;
			nxt[j]=i;
		}
		edb=nxt[c];
		for(int i=0;i<=c;i++){
			for(int k=0;k<=2;k++){
				int p=i;
				while(p&&a[p+1]!=k)p=nxt[p];
				if(a[p+1]==k)p++;
				nxtb[i][k]=p;
			}
		}
		now=0,lim=1<<(m-c+1);
		clear();
		f[0][0][0][0]=1;
		for(int i=1;i<=n;i++){
			now^=1;
			clear();
			for(int s=0;s<lim;s++)
			for(int x=0;x<c;x++)
			for(int y=0;y<c;y++)
			Add(f[now][s][0][0],f[now^1][s][x][y]);
			for(int j=1;j<=m;j++){
				now^=1;
				clear();
				for(int s=0;s<lim;s++)
				for(int x=0;x<c;x++)
				for(int y=0;y<c;y++)if(f[now^1][s][x][y])
				for(int k=0;k<3;k++){
					int sta=s,px=nxta[x][k],py=nxtb[y][k];
					if(j>=c&&(s&(1<<(j-c))))sta^=1<<(j-c);
					if(px==c)
						sta|=1<<(j-c),px=eda;
					if(py==c){
						if(s&(1<<(j-c)))continue;
						else py=edb;
					}
					Add(f[now][sta][px][py],f[now^1][s][x][y]);
				}
			}
		}
		int res=ksm(3,n*m);
		for(int s=0;s<lim;s++)
		for(int x=0;x<c;x++)
		for(int y=0;y<c;y++)Dec(res,f[now][s][x][y]);
		cout<<res<<'\n';
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章