题意:

给你n个硬币,你可以从中拿出来1、2、3个硬币,它们不一定要连续,你只需要保证拿出来的硬币中那个下标最大的硬币一定要是正面朝上,最后谁不能操作,谁就输了

题解:

翻硬币游戏

结论:

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

(本篇文章T代表反面朝上,H相反)

根据上面的结论我们可以对题目上输入的THTTHT(假设的一个),SG(THTTHT)=SG(TH)^SG(TTTTH),因此我们只需要求出来H、TH、TTH、TTTH......所有的SG值就可以解决这一道题

初始化SG(T)=0

SG(H),H可以一次操作变成T,所以SG(H)=mex{SG(T)}=mex{0}=1            //mex就是求最小的不在这里面的值,不是负值

SG(TH),可以一次操作变成TT,HT,所以SG(TH)=mex{SG(TT),SG(HT)}=mex{SG(T),SG(H)}=mex{0,1}=2   //根据题意取出来硬币下标最大的应该是H,所以靠右边的T都没用

SG(TTH),可以一次操作变成HHT,TTT,THT,HTT,SG(TTH)=mex{SG(HH),SG(T),SG(TH),SG(H)}=mex{SG(H)^SG(TH),SG(T),SG(TH),SG(H)}

                         mex{1^2,0,2,1}=mex{3,0,2,1}=4;

通过求sg发现规律

sg  1 2 4 7 8 11 13 14

x   0 1 2 3 4  5   6    7

找到规律,sg[x],如果x的二进制1的个数为奇数,sg[x]=2*x ,否则 sg[x]=2*x+1;

然后把各个Sg的值异或最终就是答案

找规律代码:

 1 #include <bits/stdc++.h>
2
3
4
5 using namespace std;
6
7
8
9 const int MAXN = 10005;
10
11
12
13 int SG[MAXN];
14
15 bool SGhash[MAXN];
16
17
18
19 inline int getSG(int x){
20
21 memset(SGhash,false,sizeof SGhash);
22
23 SGhash[0] = true;//翻一个硬币
24
25 for(int i=0 ; i<x ; ++i)SGhash[SG[i]] = true;//翻两个硬币
26
27 for(int i=0 ; i<x ; ++i)
28
29 for(int j=0 ; j<i ; ++j)SGhash[SG[i]^SG[j]] = true;//翻三个硬币
30
31 for(int i=0 ; ; ++i)if(!SGhash[i])return i;
32
33 }
34
35
36
37 inline void BuildSG(int x){
38
39 memset(SG,0,sizeof SG);
40
41 SG[0] = 1;//当head-up硬币位置在0时先手必胜
42
43 for(int i=1 ; i<=x ; ++i){
44
45 SG[i] = getSG(i);
46
47 }
48
49 }
50
51
52
53 int main(){
54
55
56
57 BuildSG(100);
58
59 for(int i=0 ; i<11 ; ++i)printf("%d:%d ",i,SG[i]);
60
61 printf("\n");
62
63 for(int i=11 ; i<20 ; ++i)printf("%d:%d ",i,SG[i]);
64
65
66
67 return 0;
68
69 }

代码:

 1 #include <iostream>
2 #include <cstdio>
3 #include <set>
4 using namespace std;
5
6 int sg(int x){
7 int ans=0,tmp=x;
8 while( x>0 ){
9 if( (x&1) ) ans++;
10 x/=2;
11 }
12 if( (ans&1) ) return 2*tmp;
13 else return 2*tmp+1;
14 }
15
16 int main(){
17 int n,x;
18 while(scanf("%d",&n)!=EOF){
19 int ans=0,x;
20 set <int> mys;
21 for(int i=0;i<n;i++){
22 scanf("%d",&x);
23 mys.insert(x);
24 }
25 for(set <int>::iterator it=mys.begin();it!=mys.end();it++){
26 ans^=sg(*it);
27 }
28 if(ans==0) printf("Yes\n");
29 else printf("No\n");
30 }
31 return 0;
32 }

最新文章

  1. JSP基本语法小结
  2. Windows下搭建IOS开发环境(一)
  3. SpringMVC 基于注解的Controller详解
  4. 2 TKinter绑定事件
  5. tomcat环境变量配置
  6. conv2用法
  7. 02C#基础(1)
  8. 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)
  9. c语言,结构体
  10. 51nod 1103 N的倍数 思路:抽屉原理+前缀和
  11. Java服务器内存过高&amp;CPU过高问题排查
  12. meta的日常设置
  13. [Oracle]快速构造大量数据的方法
  14. tomcat8 web工程启动,登陆页面失败问题解决
  15. 第二十二天- 序列化 pickle json shelve
  16. #001 GIT创建分支
  17. WF4.0(3)----变量与参数
  18. PHP curl_setopt函数用法介绍上篇
  19. [Mysql 查询语句]——对查询结果进一步的操作
  20. Python--线性代数篇

热门文章

  1. SpringBoot配置文件(2)
  2. 【Linux】CentOS4 系统最后的网络yum源
  3. LeetCode349. 两个数组的交集
  4. 阿里云 RTC QoS 屏幕共享弱网优化之若干编码器相关优化
  5. 24V转3.3V稳压芯片,高效率同步降压DC-DC变换器3A输出电流
  6. 【Android】编译报错 Annotation processors must be explicitly declared now 解决方案
  7. Memcached与Redis对比及其优劣分析
  8. ShardingSphere内核原理 原创 鸽子 架构漫谈 2021-01-09
  9. How does Circus stack compare to a classical stack?
  10. 线性DP总结(studying