题目链接: 见这里
题意: 有n堆石子,分别有a1,a2,”’,an个。两个游戏者轮流操作,每次可以选择一堆,拿走至少石子,但不能拿走超过一半的石子。比如,有3堆石子,每堆分别有5,1,2个,则再下一轮中,游戏者可以从第一堆中拿1个或者2个,第2堆中不能拿,第3堆只能拿一个。谁不能拿石子,谁就输。
解题方法:本题和NIM游戏有些差别,但是也可以看做n个单堆游戏之和。遗憾的是,即是是单堆游戏,由于ai的范围太大,也不能定义递推出所有的sg函数。但是我们可以递推出小范围的sg函数,看看有没有规律:
小范围打表程序如下:
//LA 5059 SG打表
#include <stdio.h>
#include <string.h>
const int maxn = 100;
int SG[maxn];
int vis[maxn];
int main()
{
SG[1] = 0;
for(int i = 2; i <= 30; i++){
memset(vis, 0, sizeof(vis));
for(int j = 1; j * 2 <= i; j++) vis[SG[i - j]] = 1;
for(int j = 0; ; j++){
if(!vis[j]){
SG[i] = j;
break;
}
}
printf("%d\n", SG[i]);
}
return 0;
}
/*
1 0 2 1 3 0 4 2 5 1 6 3 7 0 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15
当n为偶数时,SG(n) = n/2,但n为奇数时似乎没有什么规律.但是当把n为偶数的值全部删除后得到的数列为
0 1 0 2 1 3 0 4 2 5 1 6 3 7
*/
所以就开心写出AC代码了
//LA 5059 main.cpp
#include <bits/stdc++.h>
using namespace std;
long long SG(long long x){
return x%2 == 0 ? x / 2 : SG(x / 2);
}
int main()
{
int T; scanf("%d", &T);
while(T--){
int n;
long long a, v = 0;
cin >> n;
for(int i = 0; i < n; i++){
cin >> a;
v ^= SG(a);
}
if(v) puts("YES");
else puts("NO");
}
return 0;
}