[POI2000]条纹

Posted by Dispwnl on April 21, 2019

题目

Description

条纹游戏是一个双人的游戏。所需要的物品有一个棋盘以及三种颜色的长方形条纹,这三种颜色分别是红色、绿色和蓝色。所有的红色条纹的尺寸是$c\times 1$,所有的绿色条纹的尺寸是$z\times 1$,所有的蓝色条纹的尺寸是$n\times 1$,这里c,z,n是正整数。每种颜色的条纹每个游戏者都拥有无限多个。

一个棋盘是一个尺寸为$p\times 1$的长方形,由p个$1\times 1$的方格组成。

游戏者轮流走,每一步都是由一个游戏者任选一种长方形条纹覆盖到棋盘上,并要求遵循以下规则:

l 条纹不能伸出棋盘之外。

l 不能覆盖在已有的条纹之上(即使部分也不行)。

l 条纹的边缘必须与棋盘方格的边缘相重叠。谁不能再走,谁就输了。

先手是指在游戏中第一个走的游戏者。那么是否不管后手怎么走,先手都有必胜策略呢?

任务:

写一个程序:

l 读入条纹的尺寸以及至少一个棋盘的尺寸。

l 对每一个给出的棋盘判断先手是否必胜。

l 将结果输出。

Input

第一行包含三个整数c,z,n(1<=c,z,,n<=1000),表示三种条纹的长度,依次为红色,绿色以及蓝色。每两个数之间都用空格隔开。

文件的第二行包括一个整数m(1 <= m <= 1000)表示需要考虑的不同棋盘个数。以下3到m+2行每行包括一个整数p(1<=p<=1000)。第i+2行表示第i个棋盘的长度。

Output

应当包含m行。只有一个数字应当被写入文件的第i行:

l 1—如果对第i个棋盘先手有必胜策略。

l 2—其它。

Sample Input

1 5 1
3 
1 
5 
6 

Sample Output

1
1 
2

题解

每次操作会使棋盘分成两个部分(可以为$0$),所以可以看成有一堆$m$个石子,每次可以选一堆拿走$c,n,z$个石子并使这一堆分成两堆,这样就是$Multi-SG$游戏了

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
using namespace std;
const int MAX=1e3+5;
int c,z,n,m;
int sg[MAX];
bool use[MAX];
int main()
{
	scanf("%d%d%d%d",&c,&z,&n,&m);
	memset(sg,-1,sizeof(sg));
	for(int x=1,Mx=-1,w;x<=m;++x)
	  {
	  	scanf("%d",&w);
	  	for(int i=Mx+1;i<=w;++i)
	  	  {
	  	  	memset(use,0,sizeof(use));
	  	  	for(int j=0;j<=i-c;++j)
	  	  	  use[sg[j]^sg[i-c-j]]=1;
	  	  	for(int j=0;j<=i-z;++j)
	  	  	  use[sg[j]^sg[i-z-j]]=1;
	  	  	for(int j=0;j<=i-n;++j)
	  	  	  use[sg[j]^sg[i-n-j]]=1;
	  	  	for(int j=0;j<=i+1&&sg[i]==-1;++j)
	  	  	  if(!use[j]) sg[i]=j;
		  }
		Mx=max(Mx,w),printf("%d\n",sg[w]?1:2);
	  }
	return 0;
}