SG函数
记F(S)为集合S中没有出现的最小的非负整数
SG(u)=F({SG(v)|v为u的儿子(即v状态可以推到u状态)})
SG(all)=SG(
u1
)^SG(
u2
)^…^SG(
un
)
http://www.gdfzoj.com/oj/problem/107
Problem Description
Alice 和 Bob 总喜欢聚在一起玩游戏(T_T),今天他(她)们玩的是一款新型的取石子游戏。游戏一开始有N堆石子,Alice 和 Bob 轮流取出石子。在每次操作中,游戏者必须选择其中的一堆石子,并作出下列的其中一种操作:
(1)移去整堆石子
(2)假设石子堆中有X颗石子,取出Y颗石子,其中1<=
Y<
X,并且X和Y的最大公约数是1。
游戏结束的条件是:取出最后一颗石子的人胜出。众所周知,Alice和Bob都是绝顶聪明的,假设他们在游戏中都采取最优的策略,问最后谁会胜出游戏呢?
Input
第一行包含一个整数T,表示测试数据的组数。
接下来T组测试数据,在每组数据中,第一行包含一个整数N,表示有多少堆石子。第二行N个正整数,分别表示每堆有多少颗石子。
20%的数据,N<=5,每堆石子数量少于10
100%的数据,T<=100,N<=100,每堆石子数量不大于1,000,000
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
结论???
:SG(x)=rank(d),d为x的最小质因子,
rank(d)表示d在质数表中的排名+1
简单的进行一下证明:(希望不要被叉)
首先sg[0],sg[1]易知。
小结论1:
假设当前数为N,且
N=pk11∗pk22∗…pknn(p1<p2<…pn)
,则N一定取不到
p1
,即sg[N]<=sg[
p1
].
小结论2:
假设当前数为质数K,则其一定可以取到0~K-1,所以必须与前面的都不一样,显然质数的sg函数应该是单调递增的,由结论1可知,0~K-1的sg值均<=0~K-1所有质数的sg值的最大值(即最大质数的sg值),即前一个质数的sg值再+1(数学归纳乱搞???)。
所以对于一个质数,其sg值为其在质数表里的排名+1(因为1的sg值是1,后面的质数都要+1)。
小结论3:
由结论1&&结论2可知sg[N]<=rank(
p1
)+1。
又N的最小质因子为
p1
,所以N和1~
p1
-1互质,所以sg[N]>=rank[
p1
]+1;
so sg[N]=rank( p1 )+1
#include <cstdio>
#define maxn 1000000+5
using namespace std;
int sg[maxn],T,n,ans,x,prime[maxn],g,vis[maxn];
int main()
{
sg[1]=1;
for (int i=2;i<=maxn;i++)
{
if (!vis[i])prime[++g]=i,sg[i]=g+1;
for (int j=1;j<=g&&prime[j]*i<maxn;j++)
{
vis[prime[j]*i]=1;
sg[prime[j]*i]=j+1;
if (i%prime[j]==0) break;
}
}
scanf("%d",&T);
while (T--)
{
ans=0;
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&x),ans^=sg[x];
if (ans) printf("Alice\n");
else printf("Bob\n");
}
return 0;
}