题意:有一个一维棋盘,有格子标号1,2,3,......有n个棋子放在一些格子上,两人博弈,只能将棋子向左移,不能和其他棋子重叠,也不能跨越其他棋子,不能超越边界,不能走的人输
思路:可以用阶梯博弈来做。
那么先简单讲一下阶梯博弈:
有一个x阶阶梯,每一阶都有一定数量的石头,每次只能把某一阶梯上任意数量(不为0)的石头往下移动一阶,最多只能移动到地面,不能移动的败。这里先手的策略是这样:对奇数阶阶梯的石子进行Nim博弈,异或和为0必败。为什么不用考虑偶数呢?因为如果后手的人把m颗石头从2*n阶移到2*n-1阶,那么先手的可以把m颗石头从2*n-1阶移到2*n-2阶,重复操作直到到0阶即地面,所以我们可以不考虑偶数阶的石子数。所以奇数阶的石子被移到下一阶时,我们可以直接认为这些石头被移除了。那么直接Nim博弈就可以了。
返回这道题,如图,假如我们把棋子A向左移动一定数量,那么我们可以把棋子B向左移动相同数量来保证AB间隔不变,这里就和阶梯博弈时移动偶数阶石子奇数阶石子数量不变是一样的。所以我们从最后一个棋子开始往前分组,两个一组,每一组的间隔就是奇数阶石子个数。讲一下为什么从最后面开始分,因为最后一个间隔不会因为其他间隔的变化而变小,所以必须作为奇数阶石子保持不变(强行这样理解)。
代码:
#include<set> #include<map> #include<stack> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> typedef long long ll; const int maxn = 1000 + 10; const int seed = 131; const ll MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; int a[maxn]; int main(){ int T, n; scanf("%d", &T); while(T--){ scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + n + 1); int ans = 0; for(int i = n; i > 0; i -= 2){ ans ^= (a[i] - a[i - 1] - 1); } if(ans == 0) printf("Bob will win\n"); else printf("Georgia will win\n"); } return 0; }
原文地址:https://www.cnblogs.com/KirinSB/p/9678381.html
时间: 2024-11-29 03:55:57