Description
小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取
的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不取,我们规定取到最后一
粒石子的人算输。小约翰相当固执,他坚持认为先取的人有很大的优势,所以他总是先取石子,而他的哥哥就聪明
多了,他从来没有在游戏中犯过错误。小约翰一怒之前请你来做他的参谋。自然,你应该先写一个程序,预测一下
谁将获得游戏的胜利。
Input
本题的输入由多组数据组成第一行包括一个整数T,表示输入总共有T组数据(T≤500)。每组数据的第一行包
括一个整数N(N≤50),表示共有N堆石子,接下来有N个不超过5000的整数,分别表示每堆石子的数目。
Output
每组数据的输出占一行,每行输出一个单词。如果约翰能赢得比赛,则输出“John”,否则输出“Brother”
,请注意单词的大小写。
Sample Input
2
3
3 5 1
1
1
Sample Output
John
Brother
前言
定义(mex)函数的值为不属于集合(S)中的最小非负整数,即:
例如(mex(lbrace 0,2,4 brace)=1)。 对于状态(x)和它的所有(k)个后继状态(y_1,y_2,...,y_n),定义(SG)函数:
有向图游戏的和的SG函数值等于它包含的各个子游戏SG函数值的异或和,即:
解题报告
我们先考虑剩下石堆石子数都为1的情况。当石堆的个数为奇数时,此时处于必输态(SG值=奇数个1异或=1),反则当石堆的个数为偶数时处于必赢态(SG值=0)。
如果剩下石堆石子数存在至少两个石堆大于1的情况,如果此时SG值不等于0,由于(SG(G)=SG(G_1)igoplus SG(G_2)igoplus ...igoplus SG(G_n)),设(SG(G))的二进制表示下最高位的1在第k位,你们至少存在一堆石子(SG(G_i)),它的第k位是1。显然(SG(G_i) igoplus x<SG(G_i)),我们从第(i)堆取走若干石子,相当于(SG(G_i) igoplus x),而(x igoplus x=0)。所以我们可以通过在一个石子堆里取走若干石子将总的(SG)值变为0。
如果只有一个石堆大于1,那么先手总可以让全1的石堆的个数变为奇数个。
结论
1、当剩下石堆石子数都为1的时,总SG值等于0必胜。
2、当剩下石堆石头数有一个大于1的时候,总SG值大于1必胜。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5+10;
int main(){
int T;
cin>>T;
while(T--)
{
int n,x,ans=0;
cin>>n;
int flag=1;
for(int i=1;i<=n;i++)
{
cin>>x;
ans^=x;
if(x!=1)
flag=0;
}
if((flag&&!ans)||(!flag&&ans))
{
printf("John
");
}
else
printf("Brother
");
}
return 0;
}
参考资料
https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html
https://oi-wiki.org/math/game-theory/