Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8880 | Accepted: 5129 |
Description
Input
Output
Sample Input
2 45 45 3 3 6 9
Sample Output
No Yes
Source
有若干堆火柴和两个玩家,两个玩家一轮轮玩,每一轮,一个玩家可以选择一堆,并从该堆中取走任意根火柴,(取走的火柴根数不能是0),如果一个玩家取完火柴后,没有火柴留下,那么这个玩家赢了。
先考虑最简单的情况:
1.如果游戏只有一堆火柴,那么玩家I通过取走所有的火柴而获胜。
2.一开始有两堆火柴,数量分别是N1,N2.
游戏的取胜并不在于N1,N2的具体值是多少,而取决他们是否相等。
若N1不等于N2,玩家1可以从大堆中取走火柴使得两堆火柴数相等,然后玩家1以后每次取得数量与玩家2的相等,最终获得胜利。
若N1=N2,玩家2每次取跟玩家1相同数量的火柴,最终获得胜利。
这样,两堆取子的获胜策略就找到了。
3.首先回忆一下,没有正整数都可以转化为相应的二进制数,例如:57(10) = 111001(2)。
于是我们可以认为每一堆火柴数有2的幂的子堆组成。这样没有57枚火柴的大堆就可以看成数量分别为2^5,2^4,2^3 ,2^0,的四个子堆组成。
先考虑各个堆大小为N1,N2,N3......Nk的取子游戏,全部转化为二进制:
N1 = as.......a2a1a0
N2 = bs.......b2b1b0
...
Nk = ms......m2m1m0
如果每一种大小的子堆数是偶数,我们就称之为平衡的,而对应位相加的是偶数的称为平衡位,否则称为非平衡位。因此取子游戏是平衡的,当且仅当
as+bs + ......+ms 是偶数
...
a1+b1 + ......+m1 是偶数
a0+b0 + ......+m0 是偶数
玩家1能在非平衡态中取胜,玩家2能在平衡态中取胜。具体就不再证明。
归根结底,取子游戏的关键在于游戏开始处于何种状态,得出此算法:
n堆火柴数量对应的n个二进制数,连续进行n-1次异或运算。若结果是非0,则说明存在非平衡位,玩家1获胜,否则,玩家2获胜。
源代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
int n,m,tmp;
int main()
{
while(~scanf("%d",&n)){
m = 0;
for(int i = 0; i < n; i++){
scanf("%d",&tmp);
m ^= tmp;
}
printf("%s\n",m?"Yes":"No");
}
return 0;
}