N个数字,两人轮流操作,每次操作可以把一个数变成一个数的因子,全部为1时游戏结束,不能操作的一方输。这题直接求因子,拿每个数的因子来做行动方案的话会T掉,所以要另想方法。注意到每次把一个数变成他的因子,等价于除以他自己的若干个质因子,实际上,每次操作就是拿走1--n个该数的质因子,那么就可以处理出每个数分解质因数后质因子的个数,将其作为石子数转化成nim游戏来做了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int N=5101000;
int prime[380000], np;
bool vis[N];
int sg[N];
void get_prime()
{
np = 0;
memset(vis, 0, sizeof(vis));
for(int i = 2; i < N; ++i)
{
if (!vis[i])
{
prime[np++] = i;
for(int j = i+i; j < N; j +=i) vis[j] = 1;
}
}
}
int dvd(int x)
{
int rx=x;
int res=0;
for (int i=0; i<np; i++)
{
while (x%prime[i]==0)
{
res++;
x/=prime[i];
}
if (vis[x]==false && x!=1)
{
res++;
break;
}
if (x==1) break;
}
return res;
}
bool used[5050000];
int a[101000];
int n,m,tt;
int main()
{
// freopen("in.txt","r",stdin);
tt=0;
get_prime();
for (int i=1; i<=5000000; i++)
sg[i]=dvd(i);
while(~scanf("%d",&n))
{
tt++;
int ans=0;
for (int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
ans=ans^sg[a[i]];
}
printf("Test #%d: ",tt);
if (ans) {
int mi=0;
for (int i=1; i<=n; i++)
{
ans^=sg[a[i]];
if (ans<sg[a[i]])
{
mi=i; break;
}
ans^=sg[a[i]];
}
printf("Alice %d\n",mi);
}
else puts("Bob");
}
return 0;
}