vjudge传送门
题目大意:
给一个GCD为1的数列,有两个人每次选出一个数把这个数-1,然后把整个数列除以新数列的GCD,询问先手和后手哪个必胜。
Solution:
不难看出这是一道博弈论,我们可以假设没有GCD的限制,那么我们怎么做呢?求数列的sum然后判断sum-n的奇偶性就可以了。类比上述情况,当这个数列全是奇数时,每次操作必然会产生一个偶数,由于新数列的GCD一定是奇数,所以说GCD并不会影响数列的值的奇偶性,所以说如果初始数列全是奇数的话,那么后手必胜,策略很简单:先手改出一个偶数,后手再把它改回去,如此往复,先手必输。
既然我们知道只有一个偶数的话先手必赢,那么类比一下,有奇数个偶数的话也会是先手必赢么?是的。证明也是很简单,在一个数上纠结奇偶显然和只有一个奇数的情况一样,如果先手后手的操作都是把偶数-1的话那么最后一个偶数一定是先手减掉的。同理,如果有偶数个偶数的话后手必胜。
然后这个题就做完了
才怪
我们还要考虑一个特殊情况:只有一个奇数,其余是偶数个偶数,这种情况先手可以不先选偶数,反而去选择那一个奇数,这样的话数列一定会产生一个大于一的GCD,我们递归的对这个数列进行处理即可。
AC代码:
#include<cstdio>
#include<iostream>
using namespace std;
int a[100010];
int n;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
bool dg()
{
long long sum=0;
bool ex=0;
int num=0;
for (int i=1;i<=n;i++)
{
sum+=a[i]-1;
if (a[i]&1) num++;
if (a[i]==1) ex=1;
}
if (ex) return sum%2;
if ((n-num)%2) return 1;
if (num==1)
{
int g=0;
for (int i=1;i<=n;i++)
if (a[i]&1) a[i]--;
for (int i=1;i<=n;i++)
g=gcd(g,a[i]);
for (int i=1;i<=n;i++)
a[i]/=g;
return dg()^1;
}
return 0;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
if (dg()) printf("First");
else printf("Second");
}