附上原题链接https://www.lydsy.com/JudgeOnline/problem.php?id=1022
反SG博弈 的SJ定理。
先说结论 先手获胜的条件有两个:
1.异或和等于0 并且对于每组小游戏的SG值全都小于等于1。
2.异或和不等于0 并且对于每组小游戏存在SG值大于1。
证明,先说第一种情况 。因为异或和等于1并且SG值全都小于等于1 先手只需要把其中一个SG值为1的游戏拿了变成SG为0 而这样总的异或和也就变成了1。而后手每次需要面对的都是SG异或和为1的情况。所以先手必胜后手必败。
然后第二种情况。 (1) 当SG值大于1的只有一组的时候。先手只需要操作最大的SG值这个数让他的值变为0或1,达到异或和为1就可以了。这样无论后手怎么操作 先手就能到 “异或和等于0 并且对于每组小游戏的SG值全都小于等于1”也就是情况一 这样的必胜态。(2) 当SG值大于1的有多组的时候。先手最开始只需要和尼姆博弈一样维护SG值的异或和等于零。而后手只有面对 “异或和等于0 并且对于每组小游戏的SG值全都小于等于1”也就是情况一才能获胜,因为先手不断的在维护SG值的异或和为零,所以后手只能面对异或和为零的情况,并且需要SG值全都小于等于1才能赢。而局面SG值大于1的不止一个,在对最后两个 SG值大于1的值 时候如果后手拿掉一个,先手也拿掉一个。如果后手不拿掉一个那么先手继续维护SG值异或和为零。综上所述第二种情况下也是先手必胜。。。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a[4100];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n ;
scanf("%d",&n);
int sum =0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum^=a[i];
}
int flag=0;
for(int i=1;i<=n;i++)
{
if(a[i]>1)
flag=1;
}
if((flag==0 &&sum) || (!sum &&flag==1 ) )///后手必胜的情况
puts("Brother");
else if( (sum==0&&flag==0) || (sum!=0&&flag) )///先手必胜
puts("John");
}
return 0;
}