hdu 3537 翻硬币 每次能翻1个 或2个 或3个
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 }
打表 找规律
发现 1 2 4 7 8.... 这些的sg值为本身的两倍 这些数字的二进制只含有奇数个1 剩余的sg值为本身的2倍+1 (比如0 3 5 6 9这些)
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 sg[1010]; 13 bool vis[1010]; 14 15 int mex(int n) //求N的SG值 16 { 17 if(sg[n] != -1)return sg[n]; 18 memset(vis,false,sizeof(vis)); 19 vis[0] = 1 ; //只有1枚硬币,后继必败 20 int i , j ; 21 for (i = 0 ; i < n ; i++) 22 vis[mex(i)] = 1 ; 23 for (i = 0 ; i < n ; i++) 24 for (j = 0 ; j < i ; j++) 25 vis[mex(i)^mex(j)] = 1 ; 26 for(i = 0;;i++) 27 if(vis[i] == false) 28 { 29 sg[n] = i; 30 break; 31 } 32 return sg[n]; 33 } 34 35 int main() 36 { 37 38 memset(sg,-1,sizeof(sg)); 39 sg[0] = 1 ; 40 for(int i = 1;i <= 200;i++) 41 sg[i] = mex(i); 42 43 cout<<sg[0]<<" "; 44 for(int i=1;i<=100;i++) 45 { 46 cout<<sg[i]<<" "; 47 if(i%10==0) 48 cout<<endl; 49 } 50 51 return 0; 52 }