jzoj4024-石子游戏【SG函数,博弈论】

正题


大意

有n堆石头,每堆石头有 ai a i 个每次可以拿走一堆或者Y个(仅当 gcd(Y,ai)=1 g c d ( Y , a i ) = 1 )。拿走最后一堆石头的人就赢了,两个人都是聪明绝顶的。


解题思路

考虑构建SG函数:

SG(x)=mex(SG(xy)(gcd(x,y)=1)   υ   0) S G ( x ) = m e x ( S G ( x − y ) ( g c d ( x , y ) = 1 )       υ       0 )

这样我们会发现如果x是质数,那么比他小的都在集合里,那么它的SG值就是之前最大的SG值+1,这样的话质数的SG值就是递增的。
我们再考虑合数,由于质数的SG值是递增的,我们会发现其实每个合数产生不了任何新的值,那么每个合数的SG值就是它的最小质因子的SG值。
这样的话质数的SG值就是它是第几个质数
我们用素数筛来计算。


代码

#include
using namespace std;
int t,n,ans,a,sg[1000001],tot;
void prime()
{
    sg[1]=1;tot=1;//第一个特判
    for (int i=2;i<=1000000;i++)
    {
        if (!sg[i])//没有被筛过
        {
          sg[i]=++tot;//统计第几个质数
          for(int j=i;j<=1000000;j+=i)
            if (!sg[j]) sg[j]=tot;//被最小的质因子筛掉
        }
    }
}
int main()
{
    scanf("%d",&t);
    prime();//预处理
    while (t--)
    {
        scanf("%d",&n);
        ans=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a);//输入
            ans^=sg[a];//就SG函数的和
        }
        printf("%s\n",ans?"Alice":"Bob");//判断赢家
    }
}

你可能感兴趣的:(博弈论)