思路
本题
题目中对于棋子移动的要求相当苛刻,如下:
把一枚棋子向左移动至少一格,不可以逾越其他棋子,不可与其他棋子重合,不可移出棋盘。
模拟几次后发现,这样移动相当于将一个棋子左边的空格移动到其右边。发现其为阶梯 NIM,只要将棋子排序之后差分,转换为阶梯 NIM 之后就可以做了。
阶梯 NIM
如果你不知道怎么做阶梯 NIM,那么我再讲一下阶梯 NIM。
阶梯 NIM 定义如下:
每次可以从一个阶梯上拿掉任意数量石子放到下一层阶梯,不能操作的为输。
它的解法如下:
只考虑奇数位上的石子,把其当作普通的 NIM 博弈做即可。
原因是如果操作偶数位上的石子,那么完全可以将其向下再挪回偶数堆。也就是对于偶数堆的操作是完全不会影响到奇数堆的。而对于奇数堆的操作,挪到第 0 堆时就无法再移动。所以只有奇数堆会影响胜负。
严格的证明我不会,读者可以到网上查阅资料。
对于本题,由于我们是倒着做阶梯 NIM,所以需要根据 n 的奇偶来决定是考虑奇数位还是偶数位。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read() {
int x = 0, f = 1;
char ch;
while ((ch = getchar()) < 48 || ch > 57)if (ch == '-')f = -1;
while (ch >= 48 && ch <= 57)x = x * 10 + ch - 48, ch = getchar();
return x * f;
}
const ll N=1e6+9;
ll t,n,a[N];
int main(){
t=read();
while(t--){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
sort(a+1,a+n+1);
for(int i=n;i>0;i--){
a[i]=a[i]-a[i-1]-1;
}
ll che=n%2;
ll ans=0;
for(int i=che;i<=n;i+=2){
ans^=a[i];
}
puts(ans==0?"Bob will win":"Georgia will win");
}
return 0;
}