题意: 就是有n个游戏,一个游戏中有两堆石子,每次你可以再多的一堆中拿走k倍的少的石子,多个游戏同时进行,每个游戏必须都玩完问你最后谁输谁赢。
思路:同样来自贾志豪2009年的集训队论文,这里也直接说结论好了:
我们感性的认知一下,这种每个游戏都要玩,同时经行的游戏,我们如何赢?贪心的想一下就是对于我们可以赢得游戏,我们要玩的尽量慢一点,拿对于我们必输的游戏我们要让他尽量结束,所以对于这中游戏我们要维护一个stept的步数,
对于我们能赢的游戏我们要取最大值,对于我们输的游戏我们要去最小值,那么先手必胜的条件就是这个游戏中的最大步数是奇数,对于证明 。。。不会 大家可以看一下贾志豪的论文,可能在不远的将来我会写一遍观后感,主要是 ,,,内容太多,啃不动啊 啊啊啊啊啊 。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1000+10; int sg[maxn][maxn]; int stept[maxn][maxn]; int getsg(int x,int y) { if(sg[x][y] != -1) return sg[x][y]; if(x > y) swap(x,y); if(x == 0){ // 如果x等于0说明游戏结束 ,这时stept 和 sg值都是0 sg[x][y] = sg[y][x] = 0; stept[x][y] = stept[y][x] = 0; return sg[x][y]; } int MIN = 9999999,MAX = -1; for(int i = x ; i <= y ; i += x)//当前游戏的子游戏 { if(getsg(x,y-i) == 0)// 这里 和敌对搜索一样,如果我们当前有一个必败态那么当前肯定是一个必胜态 { MAX = max(MAX,stept[x][y-i]+1); //之后求最大值 ,不要忘记stept[x][y-i]要+1 sg[x][y] = sg[y][x] = 1;//必胜态 } else { MIN = min(MIN,stept[x][y-i] + 1); } } if(sg[x][y] == 1) stept[x][y] = stept[y][x] = MAX; // 如果是必胜那么就是最大值 else { stept[x][y] = stept[y][x] = MIN; //反之 sg[x][y] = sg[y][x] = 0; //都是必胜态 说明当前是一个必败态 } return sg[x][y]; } int main() { int n; memset(sg,-1,sizeof(sg)); while(scanf("%d",&n)!=EOF) { int maxn = -1,x,y; for(int i =0 ;i < n ;i ++) { scanf("%d%d",&x,&y); //对于每一个游戏,得到他的sg值和他的 stept ,之后维护一个最大值 getsg(x,y); maxn = max(stept[x][y],maxn); } if(maxn&1) puts("MM"); else puts("GG"); } return 0; }