题意: 就是有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;
}