Description
Alice 和 Bob 总喜欢聚在一起玩游戏(T_T),今天他(她)们玩的是一款新型的取石子游戏。游戏一开始有N堆石子,Alice 和 Bob 轮流取出石子。在每次操作中,游戏者必须选择其中的一堆石子,并作出下列的其中一种操作:
(1)移去整堆石子
(2)假设石子堆中有X颗石子,取出Y颗石子,其中1<=Y
游戏结束的条件是:取出最后一颗石子的人胜出。众所周知,Alice和Bob都是绝顶聪明的,假设他们在游戏中都采取最优的策略,问最后谁会胜出游戏呢?
Alice先取。
Input
第一行包含一个整数T,表示测试数据的组数。
接下来T组测试数据,在每组数据中,第一行包含一个整数N,表示有多少堆石子。第二行N个正整数,分别表示每堆有多少颗石子。
Output
每组测试数据输出一行,表示获胜者的名字(Alice 或者 Bob)。
Sample Input
3
3
3 5 6
4
2 3 6 9
5
3 2 1 1000000 999999
Sample Output
Alice
Bob
Alice
Data Constraint
20%的数据,N<=5,每堆石子数量少于10
100%的数据,T<=100,N<=100,每堆石子数量不大于1,000,000
思路
考虑构造 SG 函数。
SGi = mex ( { Sgij }( i, j )=1 ∪ { 0 } )
其中 mex 表示集合中最小没有出现过的自然数。
具体为什么 SG 函数是这样子的,大致上和经典取石子游戏的思路相同。
那么这个 SG 函数如果暴力算的话,貌似是 O( C^2logC ) 的,其中 C 表示石子数。
分析一下 SG 函数值的特点。
首先 SG0 = 0 (终止态)
若 k 与 i 互质,i 总是可以从 ik 中转移过来,又有若 k 与 i 互质,ik 与 i 必定互质。
那么综上有 SGi = mex ( { Sgj }( i, j )=1 ∪ { 0 } )
若 i 是质数,那么对于小于 i 的所有正整数都可以被取到,那么 SGi则应为之前出现
过的所有 SG 值中最大者+1,我们不难发现质数们的 SG 值是递增的。
若 i 是一个合数,那么 i 肯定存在某个因子为前面出现过的质数,于是 SGi 最多为该
质因子的 SG 值。又有质数们的 SG 值是递增的,那么 SGi 就应为最小质因子的 SG 值了。
我们发现合数必定不能产生新的 SG 值,它必定为其某个质因子的 SG 值。
于是第 k 个质数的 SG 值就是 k+1 了。
类似线性筛质数的原理,我们可以线性筛出 SG 值了。
代码
#include<cstdio>
int p[1000010],f[1000010],SG[1000010],num,n,ass,t;
void get(){
for (int i=2; i<1000010; i++){
if(!f[i]) p[++num]=i,SG[i]=num+1;
for (int j=1; j<=num && (j==1 || i%(p[j-1])) && p[j]*i<1000010; j++)
f[p[j]*i]=-1,SG[p[j]*i]=j+1;
}
}
int main()
{
SG[1]=1;
get();
scanf("%d",&t);
for(int i=1; i<=t; i++,ass=0)
{
int j;
scanf("%d",&j);
for(;j;j--)
{
int x;
scanf("%d",&x);
ass^=SG[x];
}
printf(ass?"Alice\n":"Bob\n");
}
}