A Game Between Alice and Bob
Time Limit : 10000/5000ms (Java/Other) Memory Limit : 524288/262144K (Java/Other)
Total Submission(s) : 2 Accepted Submission(s) : 0
Input
This problem contains multiple test cases. The first line of each case contains only one number N (1<= N <= 100000) representing there are N numbers on the blackboard. The second line contains N integer numbers specifying the N numbers written on the blackboard. All the numbers are positive and less than or equal to 5000000.
Output
Print exactly one line for each test case. The line begins with "Test #c: ", where c indicates the case number. Then print the name of the winner. If Alice wins, a number indicating her first choice is acquired, print its index after her name, separated by a space. If more than one number can be her first choice, make the index minimal.
Sample Input
4 5 7 9 12 4 41503 15991 72 16057
Sample Output
Test #1: Alice 1 Test #2: Bob
题目大意:给定n个数,每一步都可以将某个数替换为它的因子,但不能替换为本身,两个人轮流走,直到某个人走不了他就输了。问最后谁能赢,如果先手胜输出第一步。n<=10万,每个数<=5000000.
解题思路:数论+Nim。初看起来好像无从下手,但是细想:本题要找它的因子替换他自己,那么可以从这里入手。而每个数都可以表示成x = p1^a1*p2^a2...pk^ak,pi为质数,这样每个数都由(a1+a2+..ak)个质数组成,然后就转换成若干堆质数,每次可以取走某堆的某些个质数,问最后谁取无可取。
那不是传说中的裸Nim吗?把每堆的数量异或起来,结果为0为P态,先手负,结果非0,则先手胜,如果先手胜,必能与其中某个数异或后变成p态。若结果为ans,若每个数位a[i],则判断取走的那堆必须符合条件:temp = a[t] ^ ans,temp < a[t],这样的话a[i] ^ a[j] ^...a[t] = ans可表示成a[i] ^ a[j] ^...temp ^ ans = ans, 也就是a[i] ^ a[j] ^... ^ temp = 0。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
bool flag[5000005]={0};
int cnt=0,prime[5000000];
int sg[5000005];
void Prime()
{
int i,j;
for(i=2;i<=sqrt(1.0+5000000);i++)
{
if(flag[i])
continue;
prime[cnt++]=i;
sg[i]=1;
for(j=2;j*i<=sqrt(1.0+5000000);j++)
flag[i*j]=true;
}
}
int get_sg(int n)
{
if(sg[n]!=-1)
return sg[n];
int k=0,t=n,i;
for(i=0;i<cnt&&prime[i]*prime[i]<=n;i++)
if(n%prime[i]==0)
{
while(n%prime[i]==0)
{
k++;
n/=prime[i];
}
}
if(n>1)
k++;
return sg[t]=k;
}
int main()
{
memset(sg,-1,sizeof(sg));
sg[1]=0;
Prime();
int n,cas=0,a[100000];
while(scanf("%d",&n)!=EOF)
{
int ret=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
ret^=get_sg(a[i]);
}
printf("Test #%d: ",++cas);
if(ret==0)
puts("Bob");
else
{
printf("Alice ");
for(int i=0;i<n;i++)
if(sg[a[i]]>(ret^sg[a[i]]))
{
printf("%d
",i+1);
break;
}
}
}
return 0;
}