博弈论做法!!

题面可以简化为,有一堆石子,两个人轮流取紧邻的 c,z,nc,z,n 个石子,谁不能取了谁就输了。

然后就很明显的套SG函数做。

注意!!!:

  1. 枚举要拼凑布条的起点,可以从 1终点长度+11 \rightarrow \text{终点}-\text{长度}+1

  2. 注意要提前预处理,否则每次时间复杂度太高,会爆。

  3. 每个局面包含的子状态有两种,比如起点枚举到 jj,若不取则为 j1j-1,取了下一段的长度就变为了 i(j+a1)=ija+1i-(j+a-1)=i-j-a+1,即另一个子状态,两者异或即为此状态的 SGSG 值,然后 mexmex 运算求解。

code:

#include<stdio.h>
#include<string.h>
int p,c,z,n,m;
int sg[1010];
int vis[1010];
void solve(int x)
{
	memset(sg,0,sizeof(sg));
	for(int i=1;i<=x;i++)
	{
		memset(vis,0,sizeof(vis));
		for(int j=1;j<=i-c+1;j++)
			vis[sg[j-1]^sg[i-j-c+1]]=1;
		for(int j=1;j<=i-z+1;j++)
			vis[sg[j-1]^sg[i-j-z+1]]=1;
		for(int j=1;j<=i-n+1;j++)
			vis[sg[j-1]^sg[i-j-n+1]]=1;
		for(int j=0;;j++)
			if(vis[j]==0)
			{
				sg[i]=j;
				break;
			}
	}
	return ;
}
int main()
{
	scanf("%d%d%d",&c,&z,&n);
	scanf("%d",&m);
	solve(1005);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&p);
		int ans=sg[p];
		if(ans)
			printf("1\n");
		else
			printf("2\n");
	}
	return 0;
}