取石子(一)

基础的巴什博奕

巴什博奕的重点是只有一堆

如果n % (m + 1) != 0 则先手赢,如果用普通的数组会TLE。

证明:如果n = m + 1,先手最多拿m个,肯定有剩下的,所以先手必输,所以碰到k(m + 1)的局面的人必输。

那么如果n = k(m + 1) + s,这个k 就是系数,s < m + 1,那么只要先手拿掉s个,这样后手面对的就是k(m + 1)局面,所以先手在

n % (m + 1) != 0时必输。

#include <iostream>
using namespace std;
int a[1000001];
int main(){int t,n,m;cin>>t;while(t--){cin>>n>>m;if(n % (m + 1) != 0){cout<<"Win"<<endl;}else{cout<<"Lose"<<endl;}}return 0;
}

取石子(二)

这题是尼姆博弈和巴什博奕的结合

每一堆是巴什博奕,如果巴什博奕赢了就看成是石子数为1的堆,如果输了就看成是石子数为0的堆(看做没有了),下面面对的就是尼姆博弈,如果1的堆数是2的倍数,就相当于尼姆博弈中的奇异局势,面对这种局势必输,如果石子数为1的堆数不是2的倍数,那么是非奇异局势,必赢。

#include <iostream>
using namespace std;
int main(){int N,a,b;int T;cin>>T;while(T--){cin>>N;int ans = 0; for(int i = 0; i < N; i++){cin>>a>>b;ans ^= (a % (b + 1));}if(ans) cout<<"Win"<<endl;else cout<<"Lose"<<endl;}return 0;
}

取石子(三)

真是看了半天,好多帖子都没讲清楚的感觉,男人八题之一,看上去就非常吓人,但是代码真的很简洁,有点像尼姆博弈。

但是不一样,我们可以分析,

假如有一堆石子,先手必赢(N局势),

假如有两堆石子,如果两堆的数量一样,先手必输(P局势),如果两堆数量不一样,N局势,

假如有三堆石子,先手必赢(N局势)

假如有四堆石子,如果石子数量量相同,P,如果不相同,N。

以此类推

如果有n堆石子,n为奇数,先手必赢,如果n为偶数,且石子数两两相同,先手必输,否则就赢。

我自己想肯定想不出来的感觉……

#include<iostream>
#include<cstring>
using namespace std;
int a[105];
int main(){int n;while(cin>>n && n){int flag = 0;memset(a,0,sizeof(a));for(int i = 0; i < n; i++){int t;cin>>t;a[t]++;}if(n & 1)//如果是奇数,赢定了 cout<<"Win"<<endl;else{for(int i = 0; i <= 100; i++){if(a[i] & 1){//如果不能被2除断 flag = 1;break;}}if(flag) cout<<"Win"<<endl;else cout<<"Lose"<<endl;}}return 0;
}

取石子(四)

普通的威佐夫博弈题,公式有俩,如果符合公式就是奇异局势,面对奇异局势必输,然而公式我还没看懂。先记下来

ak = (int)k * (1 + sqrt(5)/2)

bk = ak + k

然后代码就是套第一个公式,如果符合就输定了

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int main(){int a,b;while(cin>>a>>b){int n = min(a,b);int m = max(a,b);double k = (double)m - n;int temp = (int)(k * (1 + sqrt(5))/2);if(temp == n){cout<<"0"<<endl;}else cout<<"1"<<endl;}return 0;
}

取石子(五)

普通的斐波那契博弈

https://blog.csdn.net/dgq8211/article/details/7602807证明过程在这里

结论:如果n是斐波那契数先手必败

#include <iostream>
using namespace std;
long long a[100];
void fib(){a[1] = 1; a[2] = 1;for(int i = 3; i < 100; i++){a[i] = a[i - 1] + a[i - 2];}
}
int main(){long long n;fib();while(cin>>n){bool flag = false;for(int i = 2; i < 100; i++){if(n == a[i]){flag = true;break;}}if(flag) cout<<"No"<<endl;else cout<<"Yes"<<endl;}return 0;
} 

取石子(六)

这题就是简单的尼姆博弈,但是要用scanf,或者优化后的cin才能过

#include <iostream>
#include <cstdio>
using namespace std;//int a[1005];
int main(){
//  ios::sync_with_stdio(false);int n,m;
//  cin>>n;scanf("%d",&n);while(n--){int ans = 0;int temp;
//      cin>>m;scanf("%d",&m);for(int i = 0; i < m; i++){
//          cin>>temp;scanf("%d",&temp);ans ^= temp;} if(ans) //cout<<"PIAOYI"<<endl;printf("PIAOYI\n");else //cout<<"HRDV"<<endl;printf("HRDV\n"); }return 0;
}

取石子(七)

可以一个一个的分析,n为石子数,

n = 1 先手赢

n = 2 先手赢

n = 3 先手输

n = 4 先手输

n = 5 先手如果取1个,后手可以取两个,剩下两堆石子数为1的堆,先手输

先手如果取2个,后手可以取1个,剩下两堆石子数为1的堆,先手输

n = 6 先手如果取1个,后手取对面的1个,剩下两堆石子数为2的堆,先手输(尼姆博弈)

先手如果取2个,后手取对面的2个,剩下两堆石子数为1的堆,先手输

以此类推,不管先手怎么取,后手总能形成数量相等的两堆石子,使先手面对尼姆博弈中的奇异局势,从而后手获胜,所以可怜的先手只能在n <= 2时获胜,后面就憋想了。

#include <iostream>
using namespace std;
int main(){int n;while(cin>>n){if(n == 1 || n == 2){cout<<"Hrdv"<<endl;}else cout<<"Yougth"<<endl;}return 0;
}

Wythoff Game

威佐夫博弈这个博客讲的蛮好,然后这道题也是套公式就可以做出来的,注意最后要换行……我就是没换行然后WA了好多发。

#include <iostream>
#include <cmath>
using namespace std;
int a[100001][2];
int main(){int n;for(int i = 1; i <= 100000; i++){a[i][0] = i * (sqrt(5.0) + 1) / 2;a[i][1] = a[i][0] + i;}while(cin>>n){for(int i = 0; i <= n; i++){cout<<"("<<a[i][0]<<","<<a[i][1]<<")";}cout<<endl;}return 0;
}

取石子(八)

跟上面那个威佐夫博弈讲的一样,假如可以赢,分两种情况

1.从两堆中取数量一样的石子,因为从两堆中取数量一样的,所以差值不会变,还是b - a,由此算出奇异局势的两个值,与a,b大小比较,要都小,就可以输出

2.从一堆中取任意数量石子,差值从1循环到b,由差值算出min,max,如果是交叉相等有四种情况

min = a && max <= b

min = b && max <= a

max = a && min <= b

max = b && min <= a

但是第二种不可能厚,所以就是这种样子啦。

#include <iostream>
#include <cmath>
using namespace std;void swap(int &aa, int &bb){int t = aa; aa = bb; bb = t;
}int main(){int a,b,big;bool flag = false;while(cin>>a>>b && a && b){if(a > b) swap(a,b);//保证a小b大 int c = b - a;//差值 int temp = c * (sqrt(5) + 1.0) / 2.0;if(temp == a){//奇异局势 cout<<"0"<<endl;}else{//取一次使其变成奇异局势 cout<<"1"<<endl;if(c == 0){cout<<"0 0"<<endl;}else{int bb = temp + c;if(bb <= b && temp <= a){cout<<temp<<" "<<bb<<endl;}}for(int i = 1;i <= b; i++){int min = i * (sqrt(5) + 1) / 2;int max = min + i;if(min > a){break;}if(min == a && max < b){cout<<min<<" "<<max<<endl;}else if(max == b && min < a){cout<<min<<" "<<max<<endl;}else if(max == a && min < b){cout<<min<<" "<<max<<endl;}}}      }return 0;
}

取石子(九)

想不明白为什么不能直接把异或后的结果作为判断依据,如果尼姆博弈是ans == 0先手输,这里改成先手赢不就好了,为什么还要统计石子数大于1的堆数呢?

后来一看测试数据,假如有两堆石子,分别有2个石子,5个石子

先手取完一堆:不论是2还是5,对手可以把剩下的那堆取的只剩一个,那么先手就输了

先手不取完:不论是在2还是在5中取的只剩1个,对手都可以在另一堆中取的只剩一个,先手也输

在这个例子中,即使2 ^ 5 != 0 先手也是必输的,

对于反尼姆博弈,可以这样分析

如果石子数都为1:堆数为偶数时,先手必输,为奇数时,先手必胜。

如果石子数都不为1:

堆数为偶数时,先手每一步,不管是在一堆中取的只剩一个,还是都取完,后手都可以做同样的动作,最后先手是必输的。

堆数为奇数时,先手最后总可以留1个给后手,先手赢

所以,1.存在石子数大于1的堆,堆数为奇数(也就是异或结果为1)先手赢

2.石子数全为1,堆数为偶数(异或结果为0),先手赢。

#include <iostream>
using namespace std;
int main(){int m,n;cin>>m;while(m--){cin>>n;int ans = 0,temp,s = 0;for(int i = 0; i < n; i++){cin>>temp;if(temp > 1) s++;ans ^= temp;}if(ans && s || !ans && !s){cout<<"Yougth"<<endl;}else cout<<"Hrdv"<<endl;}return 0;
}

取石子(十)

学到了学到了

SG函数:sg(n) = mex(sg(m))(m是n的后一个状态) , sg函数等于mex运算上一个状态的值

那么肯定有聪明的孩子要问了,什么是mex运算,什么是m是n的后一个状态呢?

别急,咱给你细细道来,

mex运算是:在不属于当前集合的值中的最小正整数,比如说mex(1,3,5) = 0,mex= (0,2,3) = 1

m是n的后一个状态:比如说有a个石子,n操作取走x个石子,剩下了a - x个石子,m就代表,有a - x个石子。

SG定理:游戏和的SG值等于各小游戏的SG值的异或和

也就是说,把各个子游戏的值都异或,最后就可以得到答案,SG值为0就是输了,大于0就赢

情况1:只能取2的幂

sg[0] = 0

x = 1时,取走1 - f{1},剩{0},sg[1] = mex{0} = 1

x = 2时,取走2 - f{1,2},剩{0,1},sg[2] = mex{0,1} = 2

x = 3时,取走3 - f{1,2},剩{1,2},sg[3] = mex{1,2} = 0

以此类推,这种情况下sg函数值是012的循环,即n%3

情况2:没有规律

情况3:sg[n] = n

情况4:没有规律

情况5:sg[n] = 0 , 1, 0 , 1 .....

情况n(n >= 6):sg[m] = m % (n + 1)

下面的第二种情况和第四种情况都是按照sg函数的定义写的代码,应该挺好看懂的,这里就不赘述了。

//游戏和的SG函数等于各个游戏SG函数的异或和
#include <iostream>
#include <cstring>
using namespace std;
int f[25],ff[1000];
int sg2[1005],vis[1005],sg4[1005];void fib(){f[1] = 1; f[2] = 1;for(int i = 3; i <= 20; i++){f[i] = f[i - 1] + f[i - 2];}return;
}void for2(){ff[1] = 1;for(int i = 1; i <= 500; i++){ff[i + 1] = i * 2;}
}
int fun2(int n){fib();memset(sg2,0,sizeof(sg2));for(int i = 1; i <= n; i++){memset(vis,0,sizeof(vis));for(int j = 1; f[j] <= i; j++)vis[sg2[i - f[j]]] = 1;for(int j = 0; j <= n; j++){if(vis[j] == 0){sg2[i] = j;break;}}}return sg2[n];
}int fun4(int n){for2();memset(sg4,0,sizeof(sg4));for(int i = 1; i <= n; i++){memset(vis,0,sizeof(vis));for(int j = 1; ff[j] <= i; j++){vis[sg4[i - ff[j]]] = 1;}for(int j = 0; j <= n; j++){if(vis[j] == 0){sg4[i] = j;break;}}}return sg4[n];
}int main(){int n,a;while(cin>>n && n){int ans = 0;for(int i = 1; i <= n; i++){cin>>a;int sg = 0;if(i == 1){ans ^= (a % 3);}else if(i == 2){ans ^= fun2(a);}else if(i == 3){ans ^= a;}else if(i == 4){ans ^= fun4(a);}else if(i == 5){ans ^= (a % 2);}else{ans ^= (a % (i + 1));}}if(ans)cout<<"Yougth"<<endl;else cout<<"Hrdv"<<endl;}return 0;
}
取石子博弈总结(先手必胜局面)
巴什博弈 n % (m + 1) != 0
威佐夫博弈 (b - a)*(1 + sqrt(5))\2  != a (b >= a)
尼姆博弈 a1 ^ a2 ^ a3 ... != 0
斐波那契博弈 a != fib{b1,b2,b3...}(不是斐波那契数列里的数)
反尼姆博弈 a1^a2^... && n || ! a1 ^ a2 ^ ... && !n

总结完毕,如果有错漏请不吝指出哦~

【NYOJ】取石子系列总结(十一题全)相关推荐

  1. 抖音短视频数据抓取实战系列(九)——自动化Appium的环境与参数配置

    抖音短视频数据抓取实战系列(九)--自动化Appium的环境与参数配置 项目目录 1.抖音短视频数据抓取实战系列(〇)--前言 2.抖音短视频数据抓取实战系列(一)--模拟器的选择与设置 3.抖音短视 ...

  2. 抖音短视频数据抓取实战系列(〇)——前言

    前言: 博主因为项目需要抓取大量的用户信息,所以便开始在网上搜素有没有什么监测数据的方法,博主查到了两种,1.fiddler监测和2.Mitmproxy监测,通过对两者的不断研究实验,博主得出了一下对 ...

  3. 抖音短视频数据抓取实战系列(三)——Fiddler抓取抖音用户详细信息数据

    抖音短视频数据抓取实战系列(三)--Fiddler抓取抖音用户详细信息数据 项目目录 1.抖音短视频数据抓取实战系列(〇)--前言 2.抖音短视频数据抓取实战系列(一)--模拟器的选择与设置 3.抖音 ...

  4. 抖音短视频数据抓取实战系列(二)——Fiddler安装配置以及模拟器监测环境配置

    抖音短视频数据抓取实战系列(二)--Fiddler安装配置以及模拟器监测环境配置 项目目录 1.抖音短视频数据抓取实战系列(〇)--前言 2.抖音短视频数据抓取实战系列(一)--模拟器的选择与设置 3 ...

  5. 抖音短视频数据抓取实战系列(十)——获取抖音dom元素属性

    抖音短视频数据抓取实战系列(十)--获取抖音dom元素属性 项目目录 1.抖音短视频数据抓取实战系列(〇)--前言 2.抖音短视频数据抓取实战系列(一)--模拟器的选择与设置 3.抖音短视频数据抓取实 ...

  6. 抖音短视频数据抓取实战系列(十二)——抓取实战BUG总集

    抖音短视频数据抓取实战系列(十二)--抓取实战BUG总集 1.模拟器自带的Xposed框架无法安装. 2.Fiddler无法监测雷电模拟器上的数据. 3.模拟器抖音用户详情页为空(未解决). 4.pi ...

  7. 抖音短视频数据抓取实战系列(六)——Mitmproxy+python编写监测程序

    抖音短视频数据抓取实战系列(六)--Mitmproxy+python编写监测程序 项目目录 1.抖音短视频数据抓取实战系列(〇)--前言 2.抖音短视频数据抓取实战系列(一)--模拟器的选择与设置 3 ...

  8. 博弈问题-取石子(D题小牛vs小客)附取石子游戏总结

    题目: 链接:https://www.nowcoder.net/acm/contest/75/D 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言6 ...

  9. NYOJ 23 取石子

    取石子(一) 时间限制:3000 ms  | 内存限制:65535 KB 难度:2 描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游戏的规 ...

最新文章

  1. 清华自研深度学习框架「计图」开源!多项任务性能超过PyTorch
  2. 【模拟】【codeforces】451B Sort the Array
  3. HDU - 7009 树上游走(树的直径+容斥)
  4. Python3.6字符串新特性
  5. mysql索引与事务笔记_《MySQL技术内幕:InnoDB存储引擎》读书笔记五-锁、索引及事务...
  6. 同一程序在不同版本的framework下控件中英文显示的问题
  7. 数据库系统概论知识点
  8. Windows应用程序进阶2(非模态对话框 通用对话框)
  9. 【CPRI协议v7.0】CPRI 8b/10b编码Scrambling功能
  10. scum服务器在线玩家,SCUM服务器选择推荐 官服跟私服有什么区别
  11. WebStrom配置好git后文件颜色代表的含义
  12. 英文标题首字母大写规则
  13. 如何改变计算机内存配置文件,电脑内存使用率过高怎么解决?教你如何调整内存大小...
  14. Python selenium自动获取URP教务系统课表并以图片形式保存
  15. 【点赞收藏】36个顶级数据分析方法与模型!
  16. ubuntu 系列linux下载edk2链接文件
  17. Excel数据分析常用函数④——日期函数(now,today,datedif,weekday,weeknum,text)
  18. linux修改tomcat默认的8080端口号
  19. 初中生物课堂中提升学生核心素养的有效策略
  20. QQ小程序百度网盘中的文件保存和下载

热门文章

  1. 压力传感器的误差构成及减小误差办法
  2. 外媒:苹果Apple Watch7电源芯片将采用双面SiP
  3. 现代富文本编辑器Quill的模块化机制
  4. CSS——CSS常用的字体样式
  5. 找找org.springframework.web.servlet.view.InternalResourceViewResolver
  6. 宝马下一代电动汽车驾驶声效将出自汉斯·季默之手 后者曾为狮子王配音
  7. python控制手机-python + adb 实现控制手机
  8. 带有示例Linux Netstat命令
  9. 怎样有效降低测试的轮次
  10. c51语言里十六进制的乘方,C51浮点数显示、浮点数表示方法