GCD Game(nim博弈)
Alice and Bob are playing a game.
They take turns to operate. There are n numbers, a1 , a2 , … , an. Every time, the player plays in 3 steps.
1.Arbitrarily chooses one number ai.
2.Arbitrarily chooses another number x(1≤x<ai).
3. Replace the number ai with gcd(ai,x). Here, gcd(u,v) refers to the Greatest Common Divisor of u and v.
When a player can not make a single move he/she loses the game. Alice moves the first and she asks you to tell her who will win the game if both player play optimally.
Input
The first line contains a number T(1≤T≤100), the number of testcases.
For each testcase, there are two lines.
The first line contains one number n(1≤n≤106).
The second line contains n numbers a1 , a2 , … , an(1≤ai≤107).
It is guaranteed that for all testcases, ∑n≤106.
Output
For each testcase, output the answer in one line. If Alice will win the game, print “Alice”, otherwise print “Bob”.
Sample Input
2
1
1
1
2
Sample Output
Bob
Alice
题意:
爱丽丝和鲍勃正在玩游戏。
他们轮流操作。有n个数字,a1,a2,一每一次,玩家分三步进行游戏。
1.任意选择一个数字ai。
2.任意选择另一个数字x(1≤x<ai)。
3.将数字ai替换为gcd(ai,x)。这里,gcd(u,v)指的是u和v的最大公约数。
当一名玩家一步也不能移动时,他/她将输掉比赛。爱丽丝先移动,她让你告诉她,如果双方都玩得很好,谁将赢得比赛。
以下思路来自这位大佬(直接粘过来的)
思路: 实际上这就是Nim博弈。首先注意到gcd的本质。不妨设
a=p1x1p2x2…pnxn,b=p1y1p2y2…pnyn,
则gcd(x,y)=p1min(x1,y1)p2min(x2,y2)…pnmin(xn,yn)考虑把每个ai唯一分解为若干个质数幂次的乘积。因为每次x是任意选的,且gcd(ai,x)是ai的因子,所以当前玩家可以直接选择当前ai的任意因子,这样很自然的就可以把初始ai的质因子累积个数看做石子数,ai变成1则不能操作等价于此时ai的每个质因子次数为0,也就是石子数为0。用欧拉筛预处理出每个数的质因子个数,对于输入直接查询sg值然后求异或和进行普通nim博弈即可。
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1e7+10;
int p[N],book[N],num[N],cnt;
void init()
{
int i,j;
for(i=2;i<=N;i++)
{
if(!book[i])
{
p[++cnt]=i;
num[i]=1;
}
for(j=1;j<=cnt&&i*p[j]<=N;j++)
{
book[i*p[j]]=1;
num[i*p[j]]=num[i]+1;
if(i%p[j]==0)
break;
}
}
}
int main()
{
int t,n,a;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int sum=0;
while(n--)
{
scanf("%d",&a);
sum^=num[a];
}
if(!sum)
printf("Bob\n");
else
printf("Alice\n");
}
return 0;
}