HDU3595 GG and MM

题目大意

M M MM MM G G GG GG玩游戏,每轮游戏有两堆石子,玩家每次操作需要任选一个正整数 k k k,并从石子数量较多的一堆石子中取出石子数量较少的一堆石子的石子数量的 k k k倍的石子。令石子数量较少的一堆石子有 x x x个石子,石子数量较多的一堆石子有 y y y个石子,则让 y = y − k × x y=y-k\times x y=yk×x。无法操作者输。 n n n次游戏同时进行,每次每个玩家在未完成的各个游戏中进行操作,以最后结束的一轮游戏的胜负来决定最终的胜负。

M M MM MM先手。如果 M M MM MM有必胜策略,则输出 M M MM MM;否则输出 G G GG GG

有多组数据。


数据范围

1 ≤ t ≤ 100 1\leq t\leq 100 1t100 t t t为数据组数。

1 ≤ n ≤ 1000 , 1 ≤ p , q ≤ 1000 1\leq n\leq 1000,1\leq p,q\leq 1000 1n1000,1p,q1000


题解

有一道类似的题:HDU1525 Euclid‘s Game

设这两堆石子的数量为 n , m n,m n,m n ≥ m n\geq m nm,我们需要分讨论

  • 如果 n % m = = 0 n\% m==0 n%m==0,则 ( n , m ) (n,m) (n,m)是先手必胜态
  • 如果 n > 2 m n>2m n>2m,则 ( n , m ) (n,m) (n,m)一定是先手必胜态,因为
    • 如果 ( n % m , m ) (n\%m,m) (n%m,m)为先手必败态,则因为 ( n , m ) (n,m) (n,m)可以转到 ( n % m , n ) (n\%m,n) (n%m,n),所以 ( n , m ) (n,m) (n,m)为先手必胜态
    • 如果 ( n % m , m ) (n\%m,m) (n%m,m)为先手必胜态,则因为 ( n % m + m , m ) (n\%m+m,m) (n%m+m,m)只能到达 ( n % m , m ) (n\%m,m) (n%m,m),所以 ( n % m + m , m ) (n\%m+m,m) (n%m+m,m)为先手必败态,又因为 ( n , m ) (n,m) (n,m)可以到达 ( n % m + m , m ) (n\%m+m,m) (n%m+m,m),所以 ( n , m ) (n,m) (n,m)为先手必胜态
  • 如果 m ≤ n < 2 m m\leq n<2m mn<2m,则 ( n , m ) (n,m) (n,m)只能转到 ( n − m , m ) (n-m,m) (nm,m),可以根据 ( n − m , m ) (n-m,m) (nm,m)的状态来判断 ( n , m ) (n,m) (n,m)的状态,重复上述操作即可

显然,对于一轮游戏,如果一方有必胜策略,则其必胜策略所需的步数是一定的。所以,我们只需要求出每轮游戏需要的步数,求最大值,根据步数最大的那一轮的胜负情况,来推出最终的胜负情况。

code

#include
using namespace std;
int n,vt,v1,v2;
int gt(int x,int y){
	if(x<y) swap(x,y);
	if(!y) return 0;
	if(!gt(y,x%y)){
		++vt;return 1;
	}
	if(x>2*y){
		vt+=2;return 1;
	}
	++vt;
	return 0;
}
int main()
{
	while(scanf("%d",&n)!=EOF){
		v1=v2=0;
		for(int i=1,x,y;i<=n;i++){
			scanf("%d%d",&x,&y);
			vt=0;
			if(gt(x,y)) v1=max(v1,vt);
			else v2=max(v2,vt);
		}
		if(v1>v2) printf("MM\n");
		else printf("GG\n");
	}
	return 0;
}

你可能感兴趣的:(题解,c++,题解)