转自:https://blog.csdn.net/tomorrowtodie/article/details/52145645
一、心得体会
1.ACM博弈题,不会的时候觉得难于上青天,会的时候觉得没有比博弈更水的题了;
博弈题看到的第一眼觉得是难题,代码敲完顿觉水题。你可能花半个小时去找规律,然后仅花2分钟敲代码。
2.博弈是单人游戏,也可以说是自己跟自己玩,因为“双方都做出最优决策”这一点限制了,最后的结果不取决
于你是谁,不取决于你的智商,只取决于你面对的局面;
3.局面,这是博弈里面最最最重要的东西!!!(所谓SG也是指这一局面的SG),博弈是一种不公平的游戏
因为游戏开始的时候已经结束了,影响你胜负的就是你所面对的局面,因为双方采取最优策略
故而局面必然会以双方当前对自己最优的路径走下去,所以结局已经确定了
4.当你面对一个局面的时候如何做出最优的决策呢?你一定是走到了最后一步才确定了胜负,所以当前的局面
往往需要从最终的局面逆推而来(也就是从一个已知胜负的局面一步步推导其他的局面,有了这样的思想,SG
也就不那么难理解了)
5.关于SG:
入门了博弈的人都知道,博弈里面常常用到一个重要的概念 – SG。但是SG是什么?你去百度的话会有非常专业的解答,
但是那些所谓的专业绝对让人看的头疼。这里说说我所理解的博弈里面的SG(仅限博弈)
挑程里是这样解释SG值的:
除 任意一步所能转移到的子局面的SG值以外的最小非负整数。
仔细体会一下这句话,你会发现,这里对SG值的定义是递归定义的!
当前局面的SG是什么呢?请先去找当前局面的子局面的SG值。
显然,递归是有一个边界的,SG是一种递归,那么它也是有边界的,
不难发现,它的边界是没有子局面的局面(也就无法再转移的局面)
什么样的局面没有子局面呢,也就是胜负已定的局面。在第4点说到,
当前局面的最优策略是从胜负已定的最终局面逆推来的,这里的SG其实也是
说了这些,那么SG到底是什么呢?
联想当年学习递归的一个例子:
f(n) = 1 , n = 1
f(n-1) +1 ,n > 1
这样一个函数是我们学习递归时的经典例子,你说这里的F到底是什么?其实它不过是一个函数而已。
SG也是一样,它只是一个函数而已,函数这个词翻译成英语再翻译成中文,就成了“功能、作用”
那么SG的作用是什么呢?
举一个最简单的例子:
有一堆石头数量为n,两个人轮流从石堆拿{a1,a2,a3,……,ak}个石头,先取完所有石头者胜。
根据前面说的,首先找胜负已定的局面,当n=0的时候,石头被拿完了,败态
那么sg[0] = 0表示面对0个石头的局面者败,然后根据sg的定义,我们可以求出其他局面的sg值
(为了使每种局面确保有可以转移的子局面,我们假设{a1,a2,a3……,ak}里面一定有1,例如假设没有1的话
,假设为{5,6,7}那么局面4没有可以转移的子局面,这样会出现平局的情况,我们后面再说平局)
这样可以求出所有局面的sg值,然后sg的作用出来了~
我们发现,若sg[x] = 0,那么x是败态,这其中很神奇,鶸也说不清楚,只说一下胜态败态的转移
(其实光理解的话可能还是不知道什么是SG,但是看了后面的题目就能理解了并知道怎么用SG找到游戏的胜态败态了)
6.胜态与败态:
之前说了,博弈里面,游戏开始的时候已经结束了,影响你胜负的就是你所面对的局面。
也就是说,这个局面觉得了你的胜负,我们称能让你走向胜利的局面称为胜态,也是必胜态,专业术语也叫P态(积极的英语单词怎么写?)
称让你走向失败的状态称为败态,也是必败态,专业也叫N态(消极的英语单词鶸也不会拼。。。)
有一个很显然的规律:
只要当前状态可以转移到的状态中有一个是败态,那么当前状态就是胜态。
如果当前状态可以转移到的所有状态都是胜态,那么当前状态就是败态。
这两句话互为逆否命题,一眼就看出是对的就不解释了。
可以胜态败态的角度去理解下SG。
7.Nim游戏:
关于这个Nim游戏,百度的话又是一大堆乱七八糟看不下去的东西,
它的最原始的版本大概是说有N堆石头,{a1,a2,a3……,an}表示每堆的数量,两个人轮流选一个石堆拿若干石头(不能不拿),
如果轮到某个人时所有的石子堆都已经被拿空了,则判负。
这个游戏有个非常完美的结论:
令 s = a1^a2^a3….^an(^符号表示异或运算)
若 s = 0,则此局面为败态,否则为胜态
对于上面的式子,我们不难发现,当你从一个石堆拿走一些石头(即改变一个ai),一定会发生胜态和败态的转变
胜态一定会转移成败态,败态也一定有策略转移成胜态
当这个结论与SG结合,神奇的事发生
我们发现sg异或和为0的状态也是败态,否则胜态。
另外,很多游戏都可以转变为Nim的形式,例如POJ 1704(挑程上有讲解)
8.关于平局:
我们发现,一个必胜态的获得,必然是因为它可以转移到一个败态,那么是不是说相比于平局我们更倾向于败态呢?
如果有更多的败态,理论上可以转移出更多的胜态,但是孩子别太天真了啊~
博弈将“对敌人的仁慈就是对自己的残忍”这句话发挥的淋漓尽致,当你选择败态的时候,对方却不会傻傻按照你的想法给你转移胜态的
该你输的时候你还是得输,所以,在博弈里的决策,一定要是对自己最有利对对手最不利的策略才是最优策略,、
也就是说,如果实在不能赢,你一定宁可平局,也不要选择败态。例如今年HDU 多校题5754 里面马的情况
9.当初关于博弈看了很多但是都只是似懂非懂,只有做多了题才有更多的·体会
二、博弈做题技巧
做了个专题:点击打开博弈专题
题目其实好多都是做过的原题,不过以前都是自己找规律的,这次就是用SG打表找规律,通过这些题目也算是知道怎么使用SG找规律了
其中的题目大多都是打表找规律,不过也有一些有趣的题目
PS:题目选自kuangbin 的博弈分类:点击打开链接(难度的话,后面的题都蛮简单,前面的题稍难)
1.打表找规律题:
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<set>
- #define mem(a,x) memset(a,x,sizeof(a))
- using namespace std;
- typedef long long ll;
- /
- 败态:
- 10 - 18
- 163 - 324
- 2917 - 5832
- 综上:
- 败态:
- (9*18^i,18*18^i]
- i从0开始
- /
- const int N = 100000;
- int sg[N+4];
- void solve()
- {
- sg[1] = 0;
- for (int i = 2;i <= N;++i)
- {
- set<int>s;
- for (int j = 2;j <= 9;++j)
- {
- int to = i/j;
- if (i%j)to++;
- s.insert(sg[to]);
- }
- int g = 0;
- while (s.count(g)) ++g;
- sg[i] = g;
- }
- for (int i = 2000;i <= 9000;++i)
- {
- cout<<i<<” ”<<sg[i]<<endl;
- }
- }
- ll l[10],r[10];
- void init()
- {
- l[0] = 9,r[0] = 18;
- for (int i = 1;i <= 9;++i)
- {
- l[i] = 18LL*l[i-1];
- r[i] = 18LL*r[i-1];
- }
- }
- bool loser(ll x)
- {
- for (int i = 0;i <= 9;++i)
- {
- if (x>l[i]&&x<=r[i]) return 1;
- }
- return 0;
- }
- int main()
- {
- // solve();
- ll n;init();
- while (~scanf(“%I64d”,&n))
- {
- if (loser(n)) puts(“Ollie wins.”);
- else puts(“Stan wins.”);
- }
- return 0;
- }
#include<iostream>
S题和W题一样的,不说了
和S、W的意思也差不多,不过操作从乘法变成了加法,由于数据小,于是也没有找规律,直接打完所有表把规律存在表里就好
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- const int N = 10010;
- bool sg[N+4];
- int n,m;
- void turn(int n)//以败态转移
- {
- for (int i = 1;i <= m;++i)
- {
- sg[n+i] = 1;//胜态
- }
- }
- void solve()
- {
- mem(sg,0);
- sg[0] = 0;
- for (int i = 0;i <= n;++i)
- {
- if (sg[i] == 0)//败态
- {
- turn(i);
- }
- }
- }
- int main()
- {
- int T;cin>>T;
- while (T–)
- {
- cin>>n>>m;
- solve();
- if (sg[n]) puts(“Grass”);
- else puts(“Rabbit”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; const int N = 10010; bool sg[N+4]; int n,m; void turn(int n)//以败态转移 { for (int i = 1;i <= m;++i) { sg[n+i] = 1;//胜态 } } void solve() { mem(sg,0); sg[0] = 0; for (int i = 0;i <= n;++i) { if (sg[i] == 0)//败态 { turn(i); } } } int main() { int T;cin>>T; while (T--) { cin>>n>>m; solve(); if (sg[n]) puts("Grass"); else puts("Rabbit"); } return 0; }
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- bool isleap(int y)
- {
- if (y%400==0||(y%4==0&&y%100!=0)) return 1;
- else return 0;
- }
- struct Date
- {
- int y,m,d;
- Date()
- {
- y = 2001,m = 11,d = 4;
- }
- Date(int y,int m,int d):y(y),m(m),d(d){}
- bool operator == (const Date &a) const
- {
- return y==a.y&&m==a.m&&d==a.d;
- }
- bool operator < (const Date &a) const
- {
- if (y==a.y)
- {
- if (m == a.m) return d<a.d;
- return m<a.m;
- }
- return y<a.y;
- }
- Date sub()
- {
- d–;
- if (d == 0)
- {
- –m;
- if (m == 0)
- {
- m = 12;
- d = 31;
- y–;
- }
- else if (m==2)
- {
- if (isleap(y)) d = 29;
- else d = 28;
- }
- else if (m==1||m==3||m==5||m==7||m==8||m==10||m==12) d = 31;
- else d = 30;
- }
- return *this;
- }
- } ;
- map<Date,int>sg;
- bool ok(Date x)
- {
- int m = x.m;
- int d = x.d;
- if (m == 2)
- {
- if (isleap(x.y)) return d<=29;
- else return d<=28;
- }
- else if (m==1||m==3||m==5||m==7||m==8||m==10||m==12) return d<=31;
- else return d <= 30;
- }
- void output(Date d)
- {
- cout<<d.y<<” ”<<d.m<<“ ”<<d.d<<endl;
- }
- void turn(Date n)
- {
- Date s = n;
- sg[s.sub()] = 1;
- Date t = n;
- t.m–;
- if (ok(t)) sg[t] = 1;
- }
- void moni()
- {
- Date d;sg.clear();
- sg[d] = 0;//败
- // output(d);
- Date s(1900,1,1);
- for (Date i;;i.sub())
- {
- // cout<<i.y<<” ”<<i.m<<” ”<<i.d<<endl;
- if (sg[i] == 0) turn(i);
- if (i == s) break;
- }
- }
- int main()
- {
- moni();
- int T;cin>>T;
- while (T–)
- {
- Date n;
- Sint2(n.y,n.m);Sint(n.d);
- if (sg[n]) puts(“YES”);
- else puts(“NO”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
题意是对于一个数字形式的字符串,可以把每一位的数字变小(包括0,不为负),可以删去一个0以及0右边的所有数一起删除,两人轮流操作
谁移除最后一个数胜
同样逆推局面推出胜态败态
逆推的时候操作变成将数字变大,或者在后面补0及其他数字,因为长度不超过6,所以还是很简单的
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<string>
- #include<set>
- #include<sstream>
- #include<map>
- #define mem(a,x) memset(a,x,sizeof(a))
- using namespace std;
- typedef long long ll;
- const int N = 1000000;
- bool sg[N+4];
- int dig[10];
- int getdig(int x)
- {
- int len = 0;
- while (x)
- {
- dig[++len] = x%10;
- x /= 10;
- }
- return len;
- }
- int turntonum(int bit[],int n)
- {
- int num = 0;
- for (int i = 1,j = 1;i <= n;++i,j*=10)
- {
- num += bit[i]*j;
- }
- return num;
- }
- void solve(int n,int i)
- {
- if (i == 1)
- {
- n*=10;
- for (int j = 0;j <= 9;++j)
- {
- // cout<<n+j<<endl;
- sg[n+j] = 1;
- }
- }
- else if (i == 2)
- {
- n*=100;
- for (int j = 0;j <= 99;++j)
- {
- // cout<<n+j<<endl;
- sg[n+j] = 1;
- }
- }
- else if (i == 3)
- {
- n*=1000;
- for (int j = 0;j <= 999;++j)
- {
- // cout<<n+j<<endl;
- sg[n+j] = 1;
- }
- }
- else if (i == 4)
- {
- n*=10000;
- for (int j = 0;j <= 9999;++j)
- {
- // cout<<n+j<<endl;
- sg[n+j] = 1;
- }
- }
- }
- void turn(int n)//n是必败态,所有n可以转移到的状态都是必胜态
- {
- int len = getdig(n);
- for (int i = 1;i <= len;++i) //数字变大
- {
- for (int j = dig[i]+1;j <= 9;++j)
- {
- int d[10];
- memcpy(d,dig,sizeof(d));
- d[i] = j;
- int x = turntonum(d,len);
- // cout<<x<<endl;
- sg[x] = 1;
- }
- }
- //加0加数
- if (len < 6)
- {
- n *= 10;//后面加个0
- sg[n] = 1;
- int d = 5-len;
- for (int i = 1;i <= d;++i)
- {
- solve(n,i);
- }
- }
- }
- void fool()
- {
- sg[0] = 1;
- // turn(1);
- for (int i = 1;i < N;++i)
- {
- if (sg[i] == 0) turn(i);
- }
- }
- int main()
- {
- fool();
- string s;
- while (cin>>s)
- {
- if (s[0] == ‘0’) puts(“Yes”);
- else
- {
- stringstream ss(s);
- int n;
- ss>>n;
- if (sg[n]) puts(“Yes”);
- else puts(“No”);
- }
- }
- return 0;
- }
#include<iostream>
#include<cstdio> #include<cstring> #include<string> #include<set> #include<sstream> #include<map> #define mem(a,x) memset(a,x,sizeof(a)) using namespace std; typedef long long ll; const int N = 1000000; bool sg[N+4]; int dig[10]; int getdig(int x) { int len = 0; while (x) { dig[++len] = x%10; x /= 10; } return len; } int turntonum(int bit[],int n) { int num = 0; for (int i = 1,j = 1;i <= n;++i,j*=10) { num += bit[i]*j; } return num; } void solve(int n,int i) { if (i == 1) { n*=10; for (int j = 0;j <= 9;++j) { // cout<<n+j<<endl; sg[n+j] = 1; } } else if (i == 2) { n*=100; for (int j = 0;j <= 99;++j) { // cout<<n+j<<endl; sg[n+j] = 1; } } else if (i == 3) { n*=1000; for (int j = 0;j <= 999;++j) { // cout<<n+j<<endl; sg[n+j] = 1; } } else if (i == 4) { n*=10000; for (int j = 0;j <= 9999;++j) { // cout<<n+j<<endl; sg[n+j] = 1; } } } void turn(int n)//n是必败态,所有n可以转移到的状态都是必胜态 { int len = getdig(n); for (int i = 1;i <= len;++i) //数字变大 { for (int j = dig[i]+1;j <= 9;++j) { int d[10]; memcpy(d,dig,sizeof(d)); d[i] = j; int x = turntonum(d,len); // cout<<x<<endl; sg[x] = 1; } } //加0加数 if (len < 6) { n *= 10;//后面加个0 sg[n] = 1; int d = 5-len; for (int i = 1;i <= d;++i) { solve(n,i); } } } void fool() { sg[0] = 1; // turn(1); for (int i = 1;i < N;++i) { if (sg[i] == 0) turn(i); } } int main() { fool(); string s; while (cin>>s) { if (s[0] == '0') puts("Yes"); else { stringstream ss(s); int n; ss>>n; if (sg[n]) puts("Yes"); else puts("No"); } } return 0; }
M - Play a game
大胆猜测,小心求证,自己随便玩几种局面就会发现奇败偶胜(代码略)
- int n;
- while (cin>>n)
- {
- if (!n) break;
- if (n&1) puts(“ailyanlu”);
- else puts(“8600”);
- }
int n;
while (cin>>n)
{
if (!n) break;
if (n&1) puts("ailyanlu");
else puts("8600");
}
L - Good Luck in CET-4 Everybody!
依旧简单打表找规律,自己手动找规律也可以,不过为了练习下SG的运用,还是用SG打表(也比手动找规律更快更准)
具体用SG打表找规律的方法代码中见:
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- const int N = 1000;
- int sg[N+7];
- void fool()
- {
- sg[0] = 0;
- for (int i = 1;i <= N;++i)
- {
- set<int>s;
- s.insert(sg[i-1]);
- for (int j = 1;j <= 10;++j)
- {
- int to = i - (1<<j);
- if (to < 0) continue;
- s.insert(sg[to]);
- }
- int g = 0;
- while (s.count(g)) ++g;
- sg[i] = g;
- }
- for (int i = 1;i <= 70;++i)
- {
- if (sg[i] == 0) cout<<i<<endl;
- // cout<<i<<”: ”<<sg[i]<<endl;
- }
- }
- int main()
- {
- // fool();
- int n;
- while (cin>>n)
- {
- if (n%3==0)//败
- {
- puts(”Cici”);
- }
- else puts(“Kiki”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; const int N = 1000; int sg[N+7]; void fool() { sg[0] = 0; for (int i = 1;i <= N;++i) { set<int>s; s.insert(sg[i-1]); for (int j = 1;j <= 10;++j) { int to = i - (1<<j); if (to < 0) continue; s.insert(sg[to]); } int g = 0; while (s.count(g)) ++g; sg[i] = g; } for (int i = 1;i <= 70;++i) { if (sg[i] == 0) cout<<i<<endl; // cout<<i<<": "<<sg[i]<<endl; } } int main() { // fool(); int n; while (cin>>n) { if (n%3==0)//败 { puts("Cici"); } else puts("Kiki"); } return 0; }
K - kiki’s game
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- const int N = 100;
- int sg[N+4][N+4];
- bool ok(int x,int y)
- {
- return x>=1&&y>=1;
- }
- void fool()
- {
- sg[1][1] = 0;
- for (int i = 1;i <= 70;++i)
- {
- for (int j = 1;j <= 70;++j)
- {
- if (i == 1&&j == 1) continue;
- set<int>s;
- if (ok(i-1,j))
- {
- s.insert(sg[i-1][j]);
- }
- if (ok(i,j-1))
- {
- s.insert(sg[i][j-1]);
- }
- if (ok(i-1,j-1))
- {
- s.insert(sg[i-1][j-1]);
- }
- int g = 0;
- while(s.count(g)) ++g;
- sg[i][j] = g;
- }
- }
- for (int i = 1;i <= 20;++i)
- {
- for (int j = 1;j <= 20;++j)
- {
- if (sg[i][j] == 0)//败态
- {
- cout<<”(“<<i<<“,”<<j<<“)”<< endl;
- }
- }
- }
- }
- int main()
- {
- // fool();
- int n,m;
- while (cin>>n>>m)
- {
- if (n==0&&m==0) break;
- if ((n&1)&&(m&1)) puts(“What a pity!”);
- else puts(“Wonderful!”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
J - 取石子游戏
斐波那契博弈哦,必败态是斐波那契数
- #include<iostream>
- #include<cstdio>
- using namespace std;
- typedef long long ll;
- bool check(ll x)
- {
- ll f1 = 1,f2 = 1;
- ll f = 2;
- while (f <= x)
- {
- f = f1 + f2;
- if (f == x) return 1;
- f1 = f2;
- f2 = f;
- }
- return 0;
- }
- int main()
- {
- ll n;
- while (cin>>n)
- {
- if (!n) break;
- if (check(n)) puts(“Second win”);
- else puts(“First win”);
- }
- return 0;
- }
#include<iostream>
#include<cstdio> using namespace std; typedef long long ll; bool check(ll x) { ll f1 = 1,f2 = 1; ll f = 2; while (f <= x) { f = f1 + f2; if (f == x) return 1; f1 = f2; f2 = f; } return 0; } int main() { ll n; while (cin>>n) { if (!n) break; if (check(n)) puts("Second win"); else puts("First win"); } return 0; }
I - 邂逅明下
三个变量,找规律的时候不是那么容易,然后说到博弈还有一个特点就是,大胆猜测~
最后发现1~p必败,p+1~p+q必胜
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- const int N = 100000;
- int sg[N+4];
- int n,p,q;
- void turn(int n)
- {
- for (int i = p;i <= q;++i)
- {
- sg[i+n] = 1;
- }
- }
- void fool()
- {
- mem(sg,0);
- sg[0] = 1;
- for (int i = 1;i <= n;++i)
- {
- if (sg[i] == 0) turn(i);
- }
- for (int i = 1;i <= n;++i)
- {
- if (sg[i] == 0) cout<<“{“<<i<<“}”<<endl;
- }
- }
- void solve()
- {
- for (int i = 1;i <= 10;++i)
- {
- for (int j = i;j <= 10;++j)
- {
- p = i,q = j;
- n = 80;
- cout<<p<<”,”<<q<<“:”<<endl;
- fool();
- cout<<”———————————-“<<endl;
- }
- }
- }
- int main()
- {
- // solve();
- while (Sint(n) == 1)
- {
- Sint2(p,q);//fool();
- // if (sg[n]) puts(“WIN”);
- // else puts(“LOST”);
- –n;
- n%=(p+q);
- if (n < p) puts(“LOST”);
- else puts(“WIN”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; const int N = 100000; int sg[N+4]; int n,p,q; void turn(int n) { for (int i = p;i <= q;++i) { sg[i+n] = 1; } } void fool() { mem(sg,0); sg[0] = 1; for (int i = 1;i <= n;++i) { if (sg[i] == 0) turn(i); } for (int i = 1;i <= n;++i) { if (sg[i] == 0) cout<<"{"<<i<<"}"<<endl; } } void solve() { for (int i = 1;i <= 10;++i) { for (int j = i;j <= 10;++j) { p = i,q = j; n = 80; cout<<p<<","<<q<<":"<<endl; fool(); cout<<"----------------------------------"<<endl; } } } int main() { // solve(); while (Sint(n) == 1) { Sint2(p,q);//fool(); // if (sg[n]) puts("WIN"); // else puts("LOST"); --n; n%=(p+q); if (n < p) puts("LOST"); else puts("WIN"); } return 0; }
找规律,发现当右下角是1的时候必胜
插一句,这个游戏公平吗?是公平的,因为右下角是1的概率是1/2,而其他的石头怎么样不需要考虑^_^
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- int main()
- {
- int T;Sint(T);
- while(T–)
- {
- int n,m;
- Sint2(n,m);
- int s ;
- for (int i = 0;i < n;++i)
- {
- for (int j = 0;j < m;++j)
- {
- Sint(s);
- }
- }
- if (s) puts(“Alice”);
- else puts(“Bob”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; int main() { int T;Sint(T); while(T--) { int n,m; Sint2(n,m); int s ; for (int i = 0;i < n;++i) { for (int j = 0;j < m;++j) { Sint(s); } } if (s) puts("Alice"); else puts("Bob"); } return 0; }
2.Nim 游戏变形:
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- //const int N = 100;
- //int a[N];
- int main()
- {
- int n;
- int T;cin>>T;
- while (T–)
- {
- int s = 0;cin>>n;
- bool allone = 1;
- for (int i = 1,x;i <= n;++i)
- {
- Sint(x);
- s ^= x;
- if (x > 1) allone = 0;
- }
- if (allone)//奇败偶胜
- {
- if (n&1) puts(“Brother”);
- else puts(“John”);
- }
- else
- {
- if (s) puts(“John”);
- else puts(“Brother”);
- }
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
T - Be the Winner
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- int main()
- {
- int n;
- while (cin>>n)
- {
- int s = 0;bool allone = 1;
- for (int i = 1,x;i <= n;++i)
- {
- Sint(x);
- s^=x;
- if (x > 1) allone = 0;
- }
- if (allone)//奇败偶胜
- {
- if (n&1) puts(“No”);
- else puts(“Yes”);
- }
- else
- {
- if (s) puts(“Yes”);
- else puts(“No”);
- }
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- //const int N = 1000;
- //int sg[N+6];
- //int SG(int st)
- //{
- // if (sg[st]!=-1) return sg[st];
- // set<int>s;
- // s.insert(SG(0));
- // for (int i = 1;i < st;++i)
- // {
- // s.insert(SG(st-i));//拿
- // s.insert(SG(i)^SG(st-i) );//分
- // }
- // int g = 0;
- // while (s.count(g)) ++g;
- // sg[st] = g;
- // return sg[st];
- //}
- //void solve()
- //{
- // mem(sg,-1);
- // sg[0] = 0;
- // for (int i = 1;i <= 50;++i)
- // {
- // cout<<i<<” :”<<SG(i)<<endl;
- // }
- //}
- int SG(int st)
- {
- if (st == 0) return 0;
- if (st%4==0) return st-1;
- if (st%4==3) return st+1;
- return st;
- }
- int main()
- {
- // solve();
- int T;cin>>T;
- while (T–)
- {
- int n;
- Sint(n);
- int s = 0;
- for (int i = 1,x;i <= n;++i)
- {
- Sint(x);
- s ^= SG(x);
- }
- if (s) puts(“Alice”);
- else puts(“Bob”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- //const int N = 1000;
- //int sg[N+5];
- //int SG(int st)
- //{
- // if (sg[st]!=-1) return sg[st];
- // set<int>s;
- // s.insert(SG(0));
- // for (int i = 1;i < st;++i)
- // {
- // s.insert(SG(st-i));//拿
- // for (int j = 1;j+i < st;++j)
- // {
- // s.insert(SG(i)^SG(j)^SG(st-i-j));//分
- // }
- // }
- // int g = 0;
- // while (s.count(g)) ++g;
- // sg[st] = g;
- // return sg[st];
- //}
- //void solve()
- //{
- // mem(sg,-1);
- // sg[0] = 0;
- // for (int i = 1;i <= 50;++i)
- // {
- // cout<<i<<”: ”<<SG(i)<<endl;
- // }
- //}
- int SG(int st)
- {
- if (st == 0) return 0;
- if (st%8 == 0) return st-1;
- if (st%8 == 7) return st+1;
- return st;
- }
- int main()
- {
- // solve();
- int T;cin>>T;
- while (T–)
- {
- int n;
- Sint(n);
- int s = 0;
- for (int i = 1,x;i <= n;++i)
- {
- Sint(x);
- s^=SG(x);
- }
- if (s) puts(“First player wins.”);
- else puts(“Second player wins.”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
我以为算是找规律的题,不过找的不是十进制数的规律,而是二进制数的规律,本来博弈就和二进制有着密不可分的关系
所以找规律的时候也要记得考虑一下二进制(这一点不仅是博弈,记得很多其他地方也用到找二进制数的规律)
不过有文章专门讲解了这一类型的游戏的策略:博弈-翻硬币游戏
这里的规律是如果x的二进制里面1个数为奇数,sg[x]就是2x,否则是2x+1
关于unique去重函数:点击打开链接
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- int getone(int x)//返回二进制1的个数
- {
- int t = 0;
- while (x)
- {
- if (x&1) ++t;
- x>>=1;
- }
- return t;
- }
- int SG(int x)
- {
- if (getone(x)&1) return 2*x;
- else return 2*x+1;
- }
- ll a[111];
- int main()
- {
- int n;
- while (cin>>n)
- {
- ll s = 0;
- for (int i = 0;i < n;++i)
- {
- Sll(a[i]);
- }
- sort(a,a+n);
- n = unique(a,a+n)-a;
- for (int i = 0;i < n;++i)
- {
- s ^= SG(a[i]);
- }
- if (!s) puts(“Yes”);
- else puts(“No”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; int getone(int x)//返回二进制1的个数 { int t = 0; while (x) { if (x&1) ++t; x>>=1; } return t; } int SG(int x) { if (getone(x)&1) return 2*x; else return 2*x+1; } ll a[111]; int main() { int n; while (cin>>n) { ll s = 0; for (int i = 0;i < n;++i) { Sll(a[i]); } sort(a,a+n); n = unique(a,a+n)-a; for (int i = 0;i < n;++i) { s ^= SG(a[i]); } if (!s) puts("Yes"); else puts("No"); } return 0; }
3.状态转移:
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- /*
- 将非0态(胜态)转化为0态(负态)有多少种方案
- */
- const int N = 100;
- int a[N+4];
- int s;
- bool ok(int x)
- {
- int ns = s^x;//把x变成更小的数,使状态变为0
- if (ns < x) return 1;
- else return 0;
- }
- int main()
- {
- int n;
- while (cin>>n)
- {
- if (!n) break;
- s = 0;
- for (int i = 1;i <= n;++i)
- {
- Sint(a[i]);
- s ^= a[i];
- }
- if (s == 0) puts(“0”);
- else
- {
- int sun = 0;
- for (int i = 1;i <= n;++i)
- {
- if (ok(a[i])) ++sun;
- }
- Pintc(sun,’\n’);
- }
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- const int N= 2111;
- int sg[N];
- int n,m;
- void turn(int n)
- {
- for (int i = 1;i <= m;++i)
- {
- sg[n+i] = 1;
- }
- }
- void fool()
- {
- mem(sg,0);
- sg[0] = 0;
- for (int i = 0;i <= n;++i)
- {
- if (sg[i] == 0) turn (i);
- }
- }
- bool ok(int x)//将此局面给 对手,对手能否赢
- {
- mem(sg,0);
- sg[x] = 0;
- for (int i = x;i <= n;++i)
- {
- if (sg[i] == 0) turn(i);
- }
- if (sg[n] == 0)//对手不能赢
- return 1;
- else return 0;
- }
- int main()
- {
- while (cin>>n>>m)//n 是成本,m是可以加的数
- {
- fool();
- if (sg[n] == 0) puts(“none”);
- else
- {
- bool first = 1;
- for (int i = 1;i <= m;++i)
- {
- if (ok(i))
- {
- if (first)
- {
- printf(”%d”,i);
- first = 0;
- }
- else printf(“ %d”,i);
- }
- }
- puts(”“);
- }
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
4.思维王道
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- bool moni(int a,int b)
- {
- bool win = 1;
- while(1)
- {
- if (a>b) swap(a,b);
- if (b%a == 0) break;
- if (b-a>a) break;
- b -= a;
- win = !win;
- }
- return win;
- }
- int main()
- {
- int a,b;
- while (cin>>a>>b)
- {
- if (a==0&&b==0) break;
- if ( moni(a,b)) puts(“Stan wins”);
- else puts(“Ollie wins”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
include<iostream>
include<cstdio>
include<cstring>
include<algorithm>
include<queue>
include<set>
include<stack>
include<cmath>
include<map>
include<stdlib.h>
include<cctype>
include<string>
define Sint(n) scanf("%d",&n)
define Sll(n) scanf("%I64d",&n)
define Schar(n) scanf("%c",&n)
define Sint2(x,y) scanf("%d %d",&x,&y)
define Sll2(x,y) scanf("%I64d %I64d",&x,&y)
define Pint(x) printf("%d",x)
define Pllc(x,c) printf("%I64d%c",x,c)
define Pintc(x,c) printf("%d%c",x,c)
using namespace std;
typedef long long ll;
bool moni(int a,int b)
{
bool win = 1;
while(1)
{
if (a>b) swap(a,b);
if (b%a == 0) break;
if (b-a>a) break;
b -= a;
win = !win;
}
return win;
}
int main()
{
int a,b;
while (cin>>a>>b)
{
if (a==0&&b==0) break;
if ( moni(a,b)) puts("Stan wins");
else puts("Ollie wins");
}
return 0;
}
G - Game
- #define mem(a,x) memset(a,x,sizeof(a))
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- #include<set>
- #include<stack>
- #include<cmath>
- #include<map>
- #include<stdlib.h>
- #include<cctype>
- #include<string>
- #define Sint(n) scanf(“%d”,&n)
- #define Sll(n) scanf(“%I64d”,&n)
- #define Schar(n) scanf(“%c”,&n)
- #define Sint2(x,y) scanf(“%d %d”,&x,&y)
- #define Sll2(x,y) scanf(“%I64d %I64d”,&x,&y)
- #define Pint(x) printf(“%d”,x)
- #define Pllc(x,c) printf(“%I64d%c”,x,c)
- #define Pintc(x,c) printf(“%d%c”,x,c)
- using namespace std;
- typedef long long ll;
- /*
- 1. 分成一个二分图
- <span style=”white-space:pre”> </span>如果可以从A拿卡片到B,连一条从A到B的边。
- 把所有box编号x满足((x%3==0&&x%2==1) || x%3==1)这个条件的放左边,其他放右边,不难发现
- a) 只有从左边到右边的边或从右到左的边。
- b) 所有不能拿卡片出去的box都在左边。
- 2. 证明左边的box并不影响结果。假设当前从右边的局势来看属于输家的人为了
- 摆脱这种局面,从左边的某盒子A拿了n张卡片到B,因为B肯定有出去的边,对手
- 会从B再取走那n张卡片到左边,局面没有变化
- 3. 于是这就相当于所有右边的box在nim游戏。
- */
- int main()
- {
- int T;cin>>T;
- int kas = 0;
- while (T–)
- {
- int n;scanf(“%d”,&n);
- int s = 0;
- for (int i = 1,x;i <= n;++i)
- {
- scanf(”%d”,&x);
- // if ((i%2==1&&i%3==0)) continue;
- if ((i%3==0&&i%2==0)||i%3==2) s^=x;
- }
- printf(”Case %d: ”,++kas);
- if (s) puts(“Alice”);
- else puts(“Bob”);
- }
- return 0;
- }
#define mem(a,x) memset(a,x,sizeof(a))
include<iostream>
include<cstdio>
include<cstring>
include<algorithm>
include<queue>
include<set>
include<stack>
include<cmath>
include<map>
include<stdlib.h>
include<cctype>
include<string>
define Sint(n) scanf("%d",&n)
define Sll(n) scanf("%I64d",&n)
define Schar(n) scanf("%c",&n)
define Sint2(x,y) scanf("%d %d",&x,&y)
define Sll2(x,y) scanf("%I64d %I64d",&x,&y)
define Pint(x) printf("%d",x)
define Pllc(x,c) printf("%I64d%c",x,c)
define Pintc(x,c) printf("%d%c",x,c)
using namespace std;
typedef long long ll;
/*
1. 分成一个二分图
<span style="white-space:pre"> </span>如果可以从A拿卡片到B,连一条从A到B的边。
把所有box编号x满足((x%3==0&&x%2==1) || x%3==1)这个条件的放左边,其他放右边,不难发现
a) 只有从左边到右边的边或从右到左的边。
b) 所有不能拿卡片出去的box都在左边。
2. 证明左边的box并不影响结果。假设当前从右边的局势来看属于输家的人为了
摆脱这种局面,从左边的某盒子A拿了n张卡片到B,因为B肯定有出去的边,对手
会从B再取走那n张卡片到左边,局面没有变化
3. 于是这就相当于所有右边的box在nim游戏。
*/
int main()
{
int T;cin>>T;
int kas = 0;
while (T--)
{
int n;scanf("%d",&n);
int s = 0;
for (int i = 1,x;i <= n;++i)
{
scanf("%d",&x);
// if ((i%2==1&&i%3==0)) continue;
if ((i%3==0&&i%2==0)||i%3==2) s^=x;
}
printf("Case %d: ",++kas);
if (s) puts("Alice");
else puts("Bob");
}
return 0;
}
B - Gems Fight!
</div>
</div>