HDU3595 GG and MM

题目描述

GG and MM like playing a game since they are children. At the beginning of game, there are two piles of stones. MM chooses a pile of stones first, which has x stones, and then she can choose a positive number k and remove kx stones out from the other pile of stones, which has y stones (I think all of you know that y>=kx - -!). Then it comes the turn of GG, followed the rules above-mentioned as well. When someone can’t remove any stone, then he/she loses the game, and this game is finished.
Many years later, GG and MM find this game is too simple, so they decided to play N games at one time for fun. MM plays first, as the same, and the one on his/her turn must play every unfinished game. Rules to remove are as same as above, and if someone cannot remove any stone (i.e., loses the last ending game), then he/she loses. Of course we can assume GG and MM are clever enough, and GG will not lose intentionally, O(∩_∩)O~

题目翻译

GG \text{GG} GG MM \text{MM} MM 玩游戏。 MM \text{MM} MM 先操作,有 n n n 对石子堆,每次操作要对每对石子堆做以下操作,设某对石子堆的个数为 ( x , y ) (x,y) (x,y) x > y x>y x>y

  • x x x 那堆里拿走 y y y 的倍数个石子。

若有一对石子堆中有一堆为 0 0 0,就不用操作。

能做最后一次操作的人获胜。假设二人都用最佳策略。

题解

这题和 HDU1525/POJ2348 Euclid‘s Game 很像,但有点不一样。

这是 Every-sg \text{Every-sg} Every-sg 博弈,做最后一次操作的获胜。对于此类博弈,应对的方法比较特别。

我想让自己赢,对于每堆石子,如果我必败,就让他快点结束,否则,就尽可能最后结束。这样,是最有可能胜利的。

对于每堆石子,记录两人能获胜的最大步数,谁的大谁就必胜。

至于如何求最大步数,见下。

方便起见,我们假定 x > y x>y x>y

下面分类讨论:

  1. x > 2 y x>2y x>2y 时,至少有两种操作可能: ( x   m o d   y + y , y ) (x\bmod y+y,y) (xmody+y,y) ( x   m o d   y , y ) (x\bmod y,y) (xmody,y)
    如果 ( x   m o d   y , y ) (x\bmod y,y) (xmody,y) 为必败态,则先手直接转移到这个状态。步数加一
    如果 ( x   m o d   y , y ) (x\bmod y,y) (xmody,y) 为必胜态,则先手可以转移到 ( x   m o d   y + y , y ) (x\bmod y+y,y) (xmody+y,y),然后后手就只能转移到 ( x   m o d   y , y ) (x\bmod y,y) (xmody,y)。步数加二。
    这样,无论如何先手都必胜。
  2. y ∣ x y\mid x yx y = 0 y=0 y=0 时,显然先手必胜。
  3. 否则,你只能转移到 ( x − y , y ) (x-y,y) (xy,y)。步数加一

通过上面的分类,我们就可以写出代码了。实现时最好使用递归。不开 long long 见祖宗。

代码

#include
using namespace std;
int n,bs;
int SG(int x,int y)
{
    if(x>y) swap(x,y);
    if(!x) return 0;
    bs++;
    if(2*x>y) return !SG(x,y-x);
    if(SG(y%x,x)) bs++;
    return 1;
}
int main()
{
    while(~scanf("%d",&n)){
        int bs1=0,bs2=0;
        for(int i=1,x,y;i<=n;i++){
            scanf("%d%d",&x,&y);
            bs=0;
            if(SG(x,y)) bs1=max(bs1,bs);
            else bs2=max(bs2,bs);
        }
        if(bs1>bs2) puts("MM");
        else puts("GG");
    }
}

你可能感兴趣的:(算法)