解析
我的做法:打表,哦…过了。
打表观察的结论:只要不全是1,答案和正常Nim游戏相同,全是1简单讨论奇偶性即可。
证明: 全是1的正确性显然,现在考虑不全是1的时候为什么直接看异或和就行。
关键性质:当仅有一堆大于1的时候必胜。
因为我可以随意的调控接下来权值为1的个数的奇偶性。
同时,只要一开始不全是1,无论如何拿,这个状态都是必然要经历的。 因此,我们可以把它作为一个获胜的终止状态。 此时显然异或和不为0。 那么就和传统Nim的证明一样了,胜方只需要一直保证到自己走时异或和不为0即可。
bonus
很有启发性的一点是,由于Nim游戏和SG函数本质的相通性,这个结论可以推广到所有类似的Anti-SG游戏中。(Anti-SG游戏的定义:决策集合为空的状态视为胜利状态。)
把SG函数当成石子数即可。 (这个玩意好像叫 Sprague Grundy - Jia Zhihao 定理)
代码
(附打表程序)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;
const int N=2e5+100;
const int mod=1e9+9;
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline ll ksm(ll x,ll k){
ll res(1);
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
int n,m;
int a[20];
int bas=31;
inline ull Hash(int *a,int n){
ull res=0;
for(int i=1;i<=n;i++) res=res*bas+a[i];
return res;
}
map<ull,int>mp;
bool cmp(int x,int y){return x>y;}
int find(const int *x,int n){
int a[20];
memcpy(a,x,sizeof(int)*(n+1));
sort(a+1,a+1+n,cmp);
while(!a[n]&&n) --n;
if(n==0) return 1;
ull h=Hash(a,n);
if(mp.count(h)) return mp[h];
int res=0;
int b[20];
memcpy(b,a,sizeof(int)*(n+1));
for(int i=1;i<=n;i++){
for(int j=0;j<a[i];j++){
b[i]=j;
res|=find(b,n)==0;
b[i]=a[i];
}
}
return mp[h]=res;
}
int op;
int now[20];
inline int calc(int *a,int n){
int res(0);
for(int i=1;i<=n;i++) res^=a[i];
return res;
}
void dfs(int k){
if(k>m){
int op=find(now,m);
if(op==0&&calc(now,m)){
for(int i=1;i<=m;i++) printf("%d ",now[i]);
printf("(%d) op=%d",calc(now,m),op);
puts("");
}
if(op==1&&calc(now,m)==0){
for(int i=1;i<=m;i++) printf("%d ",now[i]);
printf("(%d) op=%d",calc(now,m),op);
puts("");
}
return;
}
for(int i=now[k-1];i<=n;i++){
now[k]=i;
dfs(k+1);
}
return;
}
void work(){
n=read();
int res(0),flag=1;
for(int i=1;i<=n;i++){
int x=read();
res^=x;
flag&=(x==1);
}
if((res==0)^flag) puts("Brother");
else puts("John");
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int T=read();
while(T--) work();
return 0;
}
|