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 }