N 枚硬币排成一排,有的正面朝上,有的反面朝上。我们从左开始对硬币按1 到N 编号。

第一,游戏者根据某些约束翻硬币,但他所翻动的硬币中,最右边那个硬币的必须是从正面翻到反面。

第二,谁不能翻谁输。

有这样的结论:局面的SG 值为局面中每个正面朝上的棋子单一存在时的SG 值的异或和。即一个有k个硬币朝上,朝上硬币位置分布在的翻硬币游戏中,SG值是等于k个独立的开始时只有一个硬币朝上的翻硬币游戏的SG值异或和。比如THHTTH这个游戏中,2号、3号、6号位是朝上的,它等价于TH、TTH、TTTTTH三个游戏和,即sg[THHTTH]=sg[TH]^sg[TTH]^sg[TTTTTH].我们的重点就可以放在单个硬币朝上时的SG值的求法。

这一题是每次可以翻动一个、二个或三个硬币。

初始编号从0开始。如果先手胜则输出NO
sg[i] 表示 第i个位置上为正 其余位置为反面

只有一枚硬币时 正,先手必胜,则它的后继状态的sg值为0 所以sg[0]=1.
有2枚硬币时 反正 翻2个 后继状态为sg[0] 翻1个 后继状态为 所以sg[1] = 2
....


Sample Input
0
1 //n
0 //正面朝上硬币的位置
4
0 1 2 3

Sample Output
Yes
No
Yes

 

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cstring>
 4 # include <algorithm>
 5 # include <string>
 6 # include <cmath>
 7 # include <queue>
 8 # include <list>
 9 # define LL long long
10 using namespace std ;
11 
12 int a[110];
13 
14 int SG(int x)
15 {
16     int tmp = x;
17     int cnt = 0;
18     while(tmp)
19     {
20         if(tmp&1)cnt++;
21         tmp>>=1;
22     }
23     if(cnt&1)return 2*x;
24     else return 2*x + 1;
25 }
26 
27 int main()
28 {
29     int n;
30     while(scanf("%d",&n)==1)
31     {
32         for(int i = 0;i < n;i++)
33             scanf("%d",&a[i]);
34         sort(a,a+n);
35         n = unique(a,a+n)-a;
36         int sum = 0;
37         for(int i = 0;i < n;i++)
38             sum ^= SG(a[i]);
39         if(sum)printf("No\n");
40         else printf("Yes\n");
41     }
42     return 0;
43 
44 }
View Code

相关文章: