列表

详情


NC20307. [SCOI2016]围棋

描述

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

输入描述

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

输出描述

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

示例1

输入:

3 1 1 2 
B 
W 
B 
B

输出:

6
5

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 128ms, 内存消耗: 652K, 提交时间: 2023-01-07 17:08:11

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x){
    return x=read<T>();
}
typedef long long ll;
 
co int mod=1e9+7;
int n,m,c,T,nxt[7],ta[6][3],tb[6][3],na,nb;
char a[8],b[8];
int id(char x) {return x=='B'?0:(x=='W'?1:2);}
int U,f[1024][6][6],g[1024][6][6],ans;
void up(int&x,int y) {x+=y;if(x>=mod)x-=mod;}
void clear() {for(int S=0;S<U;++S)for(int x=0;x<c;++x)for(int y=0;y<c;++y)g[S][x][y]=0;}
void copy() {for(int S=0;S<U;++S)for(int x=0;x<c;++x)for(int y=0;y<c;++y)f[S][x][y]=g[S][x][y];}
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    read(n),read(m),read(c),read(T);
    while(T--){
        scanf("%s%s",a+1,b+1);
        for(int i=1;i<=c;++i)a[i]=id(a[i]),b[i]=id(b[i]);
        for(int j=nxt[1]=0,i=2;i<=c;nxt[i++]=j){
            while(j&&a[j+1]!=a[i]) j=nxt[j];
            if(a[j+1]==a[i]) ++j;
        }
        na=nxt[c];
        for(int i=0;i<c;++i)for(int j=0,k;j<3;++j){
            for(k=i;k&&a[k+1]!=j;k=nxt[k]);
            if(a[k+1]==j) ++k;
            ta[i][j]=k;
        }
        for(int j=nxt[1]=0,i=2;i<=c;nxt[i++]=j){
            while(j&&b[j+1]!=b[i]) j=nxt[j];
            if(b[j+1]==b[i]) ++j;
        }
        nb=nxt[c];
        for(int i=0;i<c;++i)for(int j=0,k;j<3;++j){
            for(k=i;k&&b[k+1]!=j;k=nxt[k]);
            if(b[k+1]==j) ++k;
            tb[i][j]=k;
        }
        U=1<<(m-c+1);
        for(int S=0;S<U;++S)for(int x=0;x<c;++x)for(int y=0;y<c;++y)f[S][x][y]=0;
        for(int i=f[0][0][0]=1;i<=n;++i){
            clear();
            for(int S=0;S<U;++S)for(int x=0;x<c;++x)for(int y=0;y<c;++y)
                if(f[S][x][y]) up(g[S][0][0],f[S][x][y]);
            copy();
            for(int j=1;j<=m;++j){
                clear();
                for(int S=0;S<U;++S)for(int x=0;x<c;++x)for(int y=0;y<c;++y)
                    if(f[S][x][y]) for(int k=0,A,B,E;k<3;++k){
                        E=S;
                        if(j>=c) if(S>>(j-c)&1) E^=1<<(j-c); // init
                        A=ta[x][k];
                        if(A==c) E|=1<<(j-c),A=na;
                        B=tb[y][k];
                        if(B==c){
                            if(S>>(j-c)&1) continue;
                            B=nb;
                        }
                        up(g[E][A][B],f[S][x][y]);
                    }
                copy();
            }
        }
        ans=1;
        for(int i=n*m;i;--i) ans=3LL*ans%mod;
        for(int S=0;S<U;++S)for(int x=0;x<c;++x)for(int y=0;y<c;++y) up(ans,mod-f[S][x][y]);
        printf("%d\n",ans);
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 380ms, 内存消耗: 2128K, 提交时间: 2020-05-31 16:03:08

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1000000007;
const int maxn=7;
const int maxv=1<<12;
int n,m,c,Q,maxx,a1[maxn],a2[maxn],nxt1[maxn],nxt2[maxn],t1[maxn][3],t2[maxn][3],f[2][maxv][maxn][maxn],cur,ans;
char s1[maxn],s2[maxn];
inline int getid(char x)
{
	if(x=='W')return 0;
	if(x=='B')return 1;
	if(x=='X')return 2;
}
int powmod(int a,int k)
{
	ll ret=1,x=a;
	while(k)
	{
		if(k&1)ret=ret*x%mod;
		x=x*x%mod;
		k>>=1;
	}
	return (int)ret;
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&c,&Q);
	maxx=1<<(m-c+1);
	while(Q--)
	{
		scanf("%s%s",s1+1,s2+1);
		for(int i=1;i<=c;i++)a1[i]=getid(s1[i]),a2[i]=getid(s2[i]);
		for(int i=2,j=0;i<=c;i++)
		{
			while(j&&a1[j+1]!=a1[i])j=nxt1[j];
			if(a1[j+1]==a1[i])j++;
			nxt1[i]=j;
		}
		for(int i=2,j=0;i<=c;i++)
		{
			while(j&&a2[j+1]!=a2[i])j=nxt2[j];
			if(a2[j+1]==a2[i])j++;
			nxt2[i]=j;	
		}
		for(int i=0;i<c;i++)for(int j=0,k=i;j<3;j++,k=i)
		{
			while(k&&a1[k+1]!=j)k=nxt1[k];
			if(a1[k+1]==j)k++;
			t1[i][j]=k;
		}
		for(int i=0;i<c;i++)for(int j=0,k=i;j<3;j++,k=i)
		{
			while(k&&a2[k+1]!=j)k=nxt2[k];
			if(a2[k+1]==j)k++;
			t2[i][j]=k;
		}
		memset(f[0],0,sizeof f[0]);
		f[0][0][0][0]=1;cur=1;
		for(int i=1;i<=n;i++)
		{
			memset(f[cur],0,sizeof f[cur]);
			for(int j=0;j<maxx;j++)for(int a=0;a<c;a++)
			for(int b=0;b<c;b++)f[cur][j][0][0]+=f[1-cur][j][a][b],f[cur][j][0][0]%=mod;
			cur=1-cur;
			for(int j=1;j<=m;j++)
			{
				memset(f[cur],0,sizeof f[cur]);
				for(int k=0;k<maxx;k++)for(int a=0;a<c;a++)
				for(int b=0;b<c;b++)if(f[1-cur][k][a][b])
				for(int col=0;col<3;col++)
				{
					int pa=t1[a][col],pb=t2[b][col],S=k;
					if(j>=c)if((S>>j-c)&1)S^=1<<j-c;
					if(pa==c){S^=1<<j-c;pa=nxt1[c];}
					if(pb==c){if((k>>j-c)&1)continue;pb=nxt2[c];}
					f[cur][S][pa][pb]+=f[1-cur][k][a][b];
					f[cur][S][pa][pb]%=mod;
				}
				cur=1-cur;
			}
		}
		ans=powmod(3,n*m);
		for(int i=0;i<maxx;i++)for(int j=0;j<c;j++)for(int k=0;k<c;k++)
		ans=(ans-f[1-cur][i][j][k]%mod+mod)%mod;
		printf("%d\n",ans);
	}
	return 0;
}

上一题