BZOJ4572: [Scoi2016]围棋
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
B
W
B
B
Sample Output
6
5
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; }
以上是关于BZOJ4572: [Scoi2016]围棋的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1069 [SCOI2007]最大土地面积 旋转卡壳