【BZOJ】1022: [SHOI2008]小约翰的游戏John(博弈论)
http://www.lydsy.com/JudgeOnline/problem.php?id=1022
好神的博弈论。
题解见dzy的blog:http://dzy493941464.is-programmer.com/posts/39629.html
orz
题目1:有n堆石子,第i堆有A(i)颗石子。两人依次从中拿取,规定每次只能从一堆中取若干根,可将一堆全取走,但不可不取,最后取完者为胜,求必胜的方法。
令C=A(1) xor A(2) xor A(3) xor ... xor A(n),若C>0,则记为利己态,用S表示,若C=0,则记为利他态,用T表示。
【定理1】对于一个S态,一定能从一堆石子中取出若干个,使其成为T态。
【证明】既然是S态,则此时C>0,我们要使得C变为0。
设C转化为二进制后,最高位的1是第p位。那么一定存在一个A(t)的二进制最高位的1是第p位。(显然,不然C的第p位不可能是1)
然后,把第t堆石子的个数变为x=A(t) xor C。因为A(t)和C的二进制最高位的1是同一位。那么异或之后这一位就变成了0。那么x一定小于A(t)。
此时的C'=A(1) xor A(2) xor ... xor A(t) xor C xor A(t+1) xor ... xor A(n)。把C带进去,得到
C'=A(1) xor A(2) xor ... xor A(n) xor A(1) xor A(2) xor ... xor A(n)。显然C'=0。
所以,只要在第t堆石子中取出A(t)-x颗石子,就把S态变为了T态。
【定理2】对于一个T态,从任意一堆取任意个石子出来,都会变为S态。
【证明】用反证法。设此时第i堆的石子数变成了A(i')。此时C=0。如果C'>0,那么命题就成立了。
假设C'=0。则C'=A(1) xor A(2) xor ... xor A(i') xor... xor A(n)=0。
因为C=0。所以C xor C'=0。则A(1) xor A(2) xor ... xor A(i) xor... xor A(n) xor A(1) xor A(2) xor ... xor A(i') xor... xor A(n)=0。
A(i) xor A(i')=0。A(i)=A(i')明显不对了。所以命题得证。
得到了这两个定理之后,我们可以发现,任何一个S态,我们都可以通过自己的控制将它转化成T态。而对方怎么做都是将T态再转回S态,很被动。所以只要先手是S态,总是可以根据定理1得到的策略获胜。
题目2:有n堆石子,第i堆有A(i)颗石子。两人依次从中拿取,规定每次只能从一堆中取若干根,可将一堆全取走,但不可不取,最后取完者为负,求必胜的方法。
再来定义几个状态。一堆石子里只有一个石子,记为孤单堆。否则记为充裕堆。
在T态中,如果充裕堆的个数大于等于2,记为T2态,1个充裕堆,记为T1态,没有充裕堆,记为T0态。S0、S1、S2同理。
【定理3】在S0态中,若孤单堆的个数为奇数。那必输。T0态必赢。
【证明】也就是奇数个石子,每次取一个。很明显先去的人必输。
【定理4】在S1态中,方法正确就必胜。
【证明】如果孤单堆的个数是奇数,那么就把充裕堆取完;如果是偶数,就把充裕堆取的只剩1根。这样留下的就是奇数个孤单堆,对方先手。由定理3得,对方必输,己方必胜。
【定理5】S2态不可一次变为T0态。
【证明】显然,充裕堆不可能一次从2堆以上变为0。
【定理6】S2态可一次变为T2态。
【证明】由定理1得S态可以一次变为T态,而且不会一次取完整堆,那么充裕堆的个数是不会变的,由定理5得S2态不能一次变为T0态,那么转化的T态是T2态。
【定理7】T2态只能转变为S1或S2态。
【证明】由定理2得,T态一次只能变为S态。由于充裕堆数不会变为0。所以是S1或S2态。
【定理8】在S2态中,只要方法正确,就必胜。
【证明】由定理6得,先转化为T2态。由定理7,对方只能再转化回S1或S2态。由定理4,己方必胜。
【定理9】T2态必输。
【证明】同证明8。
我们得到了几个必胜态:S2,S1,T0。必输态:T2,T1,S0。
比较一下两题:
第一题的过程:S2-T2-S2-T2-.....-T2-S1-T0-S0-T0-...-S0-T0(全0)
第二题的过程:S2-T2-S2-T2-.....-T2-S1-S0-T0-S0-...-S0-T0(全0)
我们可以发现前面的过程是一样的。关键在于得到了S1态之后,怎样抉择使自己获胜。而这个是自己可以掌握的。
因此,我们只需要把T2态留给对方,迟早他会转化成S1态。己方就必胜。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mkpii make_pair<int, int>
#define pdi pair<double, int>
#define mkpdi make_pair<double, int>
#define pli pair<ll, int>
#define mkpli make_pair<ll, int>
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; } int main() {
int T=getint();
while(T--) {
int n;
read(n);
int t, x=0, k=0;
for1(i, 1, n) t=getint(), x^=t, k+=t>1;
int flag=0;
if((x&&k)||(!x&&!k)) flag=1;
flag?puts("John"):puts("Brother");
}
return 0;
}
Description
小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不取,我们规定取到最后一粒石子的人算输。小约翰相当固执,他坚持认为先取的人有很大的优势,所以他总是先取石子,而他的哥哥就聪明多了,他从来没有在游戏中犯过错误。小约翰一怒之前请你来做他的参谋。自然,你应该先写一个程序,预测一下谁将获得游戏的胜利。
Input
本题的输入由多组数据组成,第一行包括一个整数T,表示输入总共有T组数据(T≤500)。每组数据的第一行包括一个整数N(N≤50),表示共有N堆石子,接下来有N个不超过5000的整数,分别表示每堆石子的数目。
Output
每组数据的输出占一行,每行输出一个单词。如果约翰能赢得比赛,则输出“John”,否则输出“Brother”,请注意单词的大小写。
Sample Input
3
3 5 1
1
1
Sample Output
Brother
HINT
【数据规模】
对于40%的数据,T ≤ 250。
对于100%的数据,T ≤ 500。
Source
【BZOJ】1022: [SHOI2008]小约翰的游戏John(博弈论)的更多相关文章
- BZOJ 1022 SHOI2008 小约翰的游戏John 博弈论
题目大意:反Nim游戏,即取走最后一个的人输 首先状态1:假设全部的堆都是1,那么堆数为偶先手必胜,否则先手必败 然后状态2:假设有两个堆数量同样且不为1,那么后手拥有控场能力,即: 若先手拿走一堆, ...
- BZOJ.1022.[SHOI2008]小约翰的游戏John(博弈论 Anti-Nim)
题目链接 Anti-Nim游戏: 先手必胜当且仅当: 1.所有堆的石子数为1,且异或和为0 2.至少有一堆石子数>1,且异或和不为0 简要证明: 对于1:若异或和为1,则有奇数堆:异或和为0,则 ...
- bzoj 1022: [SHOI2008]小约翰的游戏John anti_nim游戏
1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1189 Solved: 734[Submit][ ...
- BZOJ 1022 [SHOI2008]小约翰的游戏John
1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1635 Solved: 1036[Submit] ...
- BZOJ 1022 [SHOI2008]小约翰的游戏John AntiNim游戏
1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1475 Solved: 932[Submit][ ...
- BZOJ 1022: [SHOI2008]小约翰的游戏John (Anti-nim)
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3134 Solved: 2003[Submit][Status][Discuss] Descripti ...
- BZOJ 1022: [SHOI2008]小约翰的游戏John【anti-SG】
Description 小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不取 ...
- BZOJ 1022: [SHOI2008]小约翰的游戏John [SJ定理]
传送门 $anti-nim$游戏,$SJ$定理裸题 规定所有单一游戏$sg=0$结束 先手必胜: $1.\ sg \neq 0,\ 某个单一游戏sg >1$ $2.\ sg = 0,\ 没有单一 ...
- 51nod 1069 Nim游戏 + BZOJ 1022: [SHOI2008]小约翰的游戏John(Nim游戏和Anti-Nim游戏)
首先,51nod的那道题就是最简单的尼姆博弈问题. 尼姆博弈主要就是判断奇异局势,现在我们就假设有三个石子堆,最简单的(0,n,n)就是一个奇异局势,因为无论先手怎么拿,后手总是可以在另一堆里拿走相同 ...
- bzoj 1022: [SHOI2008]小约翰的游戏John【anti-nim】
如果全是1,那么n是奇数先手必败 否则,xor和为0先手必败 证明见 https://www.cnblogs.com/Wolfycz/p/8430991.html #include<iostre ...
随机推荐
- ZooKeeper安装方法具体解释
ZooKeeper安装方式分为两种,一种为单机模式.一个为集群模式,集群模式须要事先正确配置hadoop集群,安装方法參考hadoop-1.2.1安装方法具体解释 单机模式安装: 1.上传并解压zoo ...
- 动画曲线demo
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...
- JavaScript 中的所有数据都是以 64 位浮点型数据(float) 来存储。浮点型数据使用注意事项。全局变量特殊之处
JavaScript 中的所有数据都是以 64 位浮点型数据(float) 来存储. 所有的编程语言,包括 JavaScript,对浮点型数据的精确度都很难确定: <!DOCTYPE html& ...
- HTML5学习笔记 拖放
拖放(Drag和drop)是html5标准的组成部分 拖放是一种常见的特性,即抓取对象以后拖到另一个位置 在html5中,拖放是标准一部分,任何元素都能够拖放. 设置元素为可拖放 首先,为了使元素可拖 ...
- XML相关转换
1.将DataTable转换成xml字符串 //将DataTable转换成xml字符串: public string ConvertDataTableToXml(DataTable dt) { Mem ...
- Android_08手机联系人编码中SimpleAdapter的使用说明
1. SimpleAdapter adapter = new SimpleAdapter(this, list1,R.layout.my_layout, new String[] { "n ...
- hdu 2066 一个人的旅行(dijkstra)
一个人的旅行 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- atitit.自动生成数据库结构脚本,或者更换数据库,基于hibernate4
atitit.自动生成数据库结构脚本,或者更换数据库,基于hibernate4 目前近况:: 更换数据库,但是是使用spring集成的. <!-- hibernate配置文件路径 --> ...
- web压力测试指标
1.TPS每秒钟完成的web请求响应数量TPS=并发数/响应时间TPS是衡量系统性能的重要指标 2.并发数时间段内,系统同时处理的web请求响应数量 3.响应时间所有web请求处理完毕的时间 4.吞吐 ...
- 02、获取 WebView 控件中,加载的 HTML 网页内容
在开发 app 的时候,WebView 是经常使用的控件.而且有时需要向 WebView 中的 html 内容 注入额外的 js 进行操作.这里记录一下在当前 WebView 控件中,获取 html ...