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 }
View Code

 

打表 找规律
发现 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 }
View Code

 

posted @ 2015-09-28 20:47  __Meng  阅读(396)  评论(0编辑  收藏  举报