石子游戏 (SG函数)

题目

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个正整数,分别表示每堆有多少颗石子。

100%的数据,T<=100N<=100,每堆石子数量不大于1000000

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

分析

题目意思相当于是有 n 堆石子,每次取与某一堆当前石子数互质的石子个数或全取完。取掉最后一颗石子的人获胜。
这种博弈题一般用SG函数做,写写画画发现,SG(x)=rank(d),其中d为x的最小质因子,rank(d)表示d在质数表中的排名+1,之后把每一堆初始石子个数的SG值异或一下,答案判断是否为零就行了。
用了一下线性筛来筛质数,这样顺便就求出了每个SG函数值。(每个数只会被筛到一次)

程序

#include <cstdio>
int p[1000010],f[1000010],SG[1000010],num,n,ans,k,T;

void get_p(){
    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_p();
    scanf("%d",&T);
    for (; T; T--,ans=0){
        for (scanf("%d",&n); n--;) ans^=SG[(scanf("%d",&k),k)];
        printf(ans ? "Alice\n":"Bob\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值