BZOJ4572: [Scoi2016]围棋

Description

近日,谷歌研发的围棋AI—AlphaGo以4:1的比分战胜了曾经的世界冠军李世石,这是人工智能领域的又一里程碑。
与传统的搜索式AI不同,AlphaGo使用了最近十分流行的卷积神经网络模型。在卷积神经网络模型中,棋盘上每一
块特定大小的区域都被当做一个窗口。例如棋盘的大小为5×6,窗口大小为2×4,那么棋盘中共有12个窗口。此外
,模型中预先设定了一些模板,模板的大小与窗口的大小是一样的。下图展现了一个5×6的棋盘和两个2×4的模板
。对于一个模板,只要棋盘中有某个窗口与其完全匹配,我们称这个模板是被激活的,否则称这个模板没有被激活
。例如图中第一个模板就是被激活的,而第二个模板就是没有被激活的。我们要研究的问题是:对于给定的模板,
有多少个棋盘可以激活它。为了简化问题,我们抛开所有围棋的基本规则,只考虑一个n×m的棋盘,每个位置只能
是黑子、白子或无子三种情况,换句话说,这样的棋盘共有3n×m种。此外,我们会给出q个2×c的模板。我们希望
知道,对于每个模板,有多少种棋盘可以激活它。强调:模板一定是两行的。
 

Input

输入数据的第一行包含四个正整数n,m,c和q,分别表示棋盘的行数、列数、模板的列数和模板的数量。随后2×q
行,每连续两行描述一个模板。其中,每行包含c个字符,字符一定是‘W’,‘B’或‘X’中的一个,表示白子、
黑子或无子三种情况的一种。N<=100,M<=12,C<=6,Q<=5

Output

 输出应包含q行,每行一个整数,表示符合要求的棋盘数量。由于答案可能很大,你只需要输出答案对1,000,000,007取模后的结果即可。

Sample Input

3 1 1 2
B
W
B
B

Sample Output

6
5
 
考虑补集转换,计算不合法的情况,然后轮廓线DP一下,状态记录为轮廓线上与第一行串是否完全匹配,当前位置与第一行串及第二行串的kmp匹配位置。
时间复杂度为O(T*N*M*2^M*C^2)
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
typedef long long ll;
const int mod=1000000007;
char id[2333];
void Add(int& x,int y) {x+=y;if(x>=mod) x-=mod;}
int to1[8][3],to2[8][3];
void init(char* A,int* f,int c,int tp) {
	id['W']='0';id['B']='1';id['X']='2';
	rep(i,0,c-1) A[i]=id[A[i]];
	rep(i,1,c-1) {
		int j=f[i];
		while(j&&A[i]!=A[j]) j=f[j];
		f[i+1]=A[i]==A[j]?j+1:0;
	}
	rep(i,0,c) rep(k,0,2) {
		int j=i;
		while(j&&A[j]!=k+'0') j=f[j];
		if(A[j]==k+'0') j++;
		if(tp) to2[i][k]=j;
		else to1[i][k]=j;
	}
}
int n,m,c,f[2][1<<12][8][8],tmp[8];
char A[8],B[8];
void solve() {
	int cur=0;scanf("%s%s",A,B);
	init(A,tmp,c,0);init(B,tmp,c,1);
	memset(f,0,sizeof(f));f[0][0][0][0]=1;
	rep(x,1,n) rep(y,1,m) {
		cur^=1;memset(f[cur],0,sizeof(f[cur]));
		rep(S,0,(1<<m)-1) rep(i,0,c) rep(j,0,c) {
			int& res=f[cur^1][S][i][j];if(!res) continue;
			rep(k,0,2) {
				int nx=to1[i][k],ny=to2[j][k],nS=S<<1;
				if(nS>>m&1) nS^=(1<<m);if(nx==c) nS^=1;
				if(y>=c&&ny==c&&(S>>(m-1)&1)) continue;
				Add(f[cur][nS][nx][ny],res);
			}
		}
	}
	int ans=1;rep(i,1,n*m) ans=(ll)ans*3%mod;
	rep(S,0,(1<<m)-1) rep(i,0,c) rep(j,0,c) Add(ans,mod-f[cur][S][i][j]);
	printf("%d\n",ans);
}
int main() {
	n=read();m=read();c=read();
	dwn(T,read(),1) solve();
	return 0;
}

  

posted @ 2016-06-11 17:25  wzj_is_a_juruo  阅读(469)  评论(0编辑  收藏  举报