石子游戏【博弈论】

题目大意:

n堆石子,两人轮流取石子,每次可以将一堆全部拿走,也可以选择其中y个拿,但是要求y与这堆石子的总个数互质。求谁会胜利。


思路:

明显的博弈论之SG函数。
我们可以发现,质数的SG值就等于上一个质数的SG值加一,而合数的SG值就是它的最小质因子的SG,所以,我们先预处理出所有质数(一遍 埃拉托斯特尼筛法 后顺便求出每个数的SG值),再遍读入遍异或,再判断是01即可。
时间复杂度:O(tn2),但是很多时间达不到n2,平均只有O(tn)


代码:

#include <cstdio>
#include <iostream>
using namespace std;

const int N=1000000;
int t,n,sg[N+50],k,ans,x;

void find_prime()  //筛质数
{
    sg[1]=k=1;
    for (int i=2;i<=N;i++)
    {
        if (sg[i]) continue;  //不是质数
        sg[i]=++k; 
        for (int j=i;j<=N;j+=i)
         if (!sg[j]) sg[j]=k;  //if语句是必须的,因为合数的SG值是它最小值因子的SG值
    }
    return;
}

int main()
{
    scanf("%d",&t);
    find_prime();
    while (t--)
    {
        scanf("%d",&n);
        ans=0;
        for (int i=1;i<=n;i++)  
        {
            scanf("%d",&x);
            ans^=sg[x];  //异或,不懂情科普博弈论普及知识
        }
        if (ans) printf("Alice\n");
         else printf("Bob\n");
    }
    return 0;
}
posted @ 2018-07-16 20:47  全OI最菜  阅读(83)  评论(0编辑  收藏  举报