BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidsummer/article/details/84344983

Description

小H和小Z正在玩一个取石子游戏。 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,
每次取石子的个数有限制,谁不能取石子时就会输掉游戏。 小H先进行操作,他想问你他是否有必胜策略,如果有
,第一步如何取石子。

Input

输入文件的第一行为石子的堆数N
接下来N行,每行一个数Ai,表示每堆石子的个数 接下来一行为每次取石子个数的种类数M
接下来M行,每行一个数Bi,表示每次可以取的石子个数,
输入保证这M个数按照递增顺序排列。
N≤10 Ai≤1000
对于全部数据,M≤10,Bi≤10

Output

输出文件第一行为“YES”或者“NO”,表示小H是否有必胜策略。
若结果为“YES”,则第二行包含两个数,第一个数表示从哪堆石子取,第二个数表示取多少个石子,
若有多种答案,取第一个数最小的答案,
若仍有多种答案,取第二个数最小的答案。

Sample Input

4

7

6

9

3

2

1

2

Sample Output

YES

1 1

Hint

样例中共有四堆石子,石子个数分别为7、6、9、3,每人每次可以从任何一堆石子中取出1个或者2个石子,小H有

必胜策略,事实上只要从第一堆石子中取一个石子即可。
HINT

思路:

由于数很小,而且每个堆都是独立的,所以我们可以暴力sg函数,
最后亦或和为 0 就是必败。

#include<bits/stdc++.h>
using namespace std;
const  int N = 1e3+100;
int a[N],b[N],sg[N];
bool vis[N];
int n,m,ans;
void get_sg(){ //sg函数。暴力sg函数。
	for (int i = 1; i < 1005; i++){
		memset(vis,0,sizeof(vis));
		for (int j = 0; j < m && b[j] <= i; j++){
			vis[sg[i - b[j]]] = 1;
		}
		for (int j = 0; j < 1006; j++)
			if (vis[j] == 0) {
				sg[i] = j;
				break;
			}
	}
}

void init(){ //初始化,读入。 
	scanf("%d",&n);
	for (int i = 0; i < n; i++)
		scanf("%d",&a[i]);
	scanf("%d",&m);
	for (int i = 0; i < m; i++)
		scanf("%d",&b[i]);
	get_sg();
}

void solve(){
	for (int i = 0; i < n; i++)
		ans ^= sg[a[i]];
	if (!ans) puts("NO"); else{
		puts("YES");
		for (int i = 0; i < n; i++){
			for (int j = 0; j < m; j++){
				if (b[j] <= a[i] && (ans ^ (sg[a[i]]) ^(sg[a[i] - b[j]])) ==  0){
					printf("%d %d\n",i + 1,b[j]);
					return;
				}
			}
		}
	}
}
int main(){
	init();
	solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/84344983
今日推荐