CF1370C Number Game (博弈论+数论)

题目

最开始,我们可以把 n n n 分成三种情况

  • n = 1 n=1 n=1,后手赢
  • n n n 为奇数,先手赢, n n n 直接除以自身就可以了

前两种情况都比较简单,下面来讨论当 n n n 为偶数的情况
n n n 为偶数( 2 2 2 的倍数),想赢的话肯定不能使用减 1 1 1 的操作,因为这样后手必胜。那么就考虑除以约数
由于 n n n 为偶数,我们一定可以将 n n n 分解成一些质数与 2 2 2 的正整数次幂之积 n = p 1 × p 2 × ⋯ × p m × 2 k n=p_1 \times p_2 \times \cdots \times p_m \times 2^k n=p1×p2××pm×2k ( k > 0 , m ≥ 0 ) (k>0,m \ge 0) (k>0,m0),并且满足这些质数都不是 2 2 2 的倍数
又因为每次除掉的值可以是多个质因数的积(只要是约数就行),所以只要 m > 1 m>1 m>1Ashishgup 就可以很灵活的选择约数。
最后,当 n n n 被除地只剩 2 k 2^k 2k 时,又会有两种情况

  1. n = 2 n=2 n=2 ,先取的人赢:判断是否能将 m m m 个质数转化成偶数个不为 1 1 1 的数的乘积,如果可以的话说明当前 Ashishgup 可以先取(Ashishgup 获胜)
  2. n > 2 n>2 n>2 ,后取的人赢:判断是否能将 m m m 个质数转化成奇数个不为 1 1 1 的数的乘积,如果可以的话说明当前 Ashishgup 可以后取(Ashishgup 获胜)

否则获胜的就是 FastestFinger

代码

#include
#include
using namespace std;
int n;
int main()
{
//	freopen("in.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		if(n==1){puts("FastestFinger");continue;}
		if((n & 1) || n==2){puts("Ashishgup");continue;}
		int tot=0;
		for(int i=2;i*i<=n;++i)
		if((i & 1) && n%i==0) // 注意这里只能把为奇数的质因数
		while(n%i==0)++tot,n/=i;
		for(int i=2;i*i<=n;++i)
		{
			int tmp=n/i;
			if((tmp & 1) && n%i==0)
			while(n%tmp==0)++tot,n/=tmp;
		}
		if(n==2)
		{
			if(tot!=1)puts("Ashishgup");
			else puts("FastestFinger"); // 如果只有一个质数的话就不能化为偶数个数之积
		}
		else
		{
			if(tot)puts("Ashishgup");
			else puts("FastestFinger"); // 这里特判的是0,跟上面原理相同
		}
	}
	return 0;
}

你可能感兴趣的:(题解,#Codeforces)