题意:给以一个1*n的棋盘,之后棋盘上面放了几个棋子,其中棋子只能向左移动,且一个格子里面只能放一个棋子,棋子不能越过他前面棋子,问你怎么赢。
思路:首先讲一下
阶梯博弈:
给以一个阶梯,每个阶梯上面放了一些石子,你每次至少移动一颗石子到下一个阶梯,谁不能移动谁输。
对于一个楼梯上面的石子来说,我往下放石子是不是就是类似与我nim游戏中的一堆石子中移走几颗石子,至于对于他的移动到的下一个阶梯来说,上面来多少个我往下面放几个之后,先手面临的状态不变,由此我们可以看出,我们需要每次隔一个阶梯进行nim(那一层隔的台阶就是为了让上一层来的石子可以移动到我们隔的那一层中,这样我们要的nim状态不会改变),就比如说我有5个台阶,每个台阶上面分别是2 ,3,6,5,先手面临奇数的台阶石子数量是 2 ,6 那么先手把第四阶移动两个变成了 2 ,3,8,3,此时我们奇数台阶的数量是 2 ,8,之后后手把移动的两个移动到第2格变成2,5,6,3,那么先手面临的奇数台阶的数量还是还是2, 6,那么为什么是奇数台阶是nim的石子堆而不是偶数呢?因为如果是偶数堆的话他要是移动到奇数堆,之后我们在把石子从奇数堆扔到偶数堆的时候会移动到0这个位置啊,那么对于胜负态就改变了。
所以总结一下阶梯博弈怎么写就是:我们把奇数堆的石子数当成nim的石子堆之后异或和一下就好了。
那么回到这道题上面,其实就是简单的阶梯博弈了我们把相邻的石子中的格子当成阶梯博弈的阶梯,之后只取奇数的阶梯就好了,如果n是奇数的话我们需要加一个0上代码把:
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
const int maxn = 1000+10;
using namespace std;
int a[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
memset(a,0,sizeof(a));
scanf("%d",&n);
for(int i = 0 ; i < n ; i++){
scanf("%d",&a[i]);
}
if(n&1)
{
a[n] = 0;
n++;
}
sort(a,a+n);
int ans = 0;
for(int i = 0 ; i < n ; i = i + 2)
{
ans = ans ^ (a[i+1] - a[i] - 1);
}
if(ans) puts("Georgia will win");
else puts("Bob will win");
}
}