• 石子游戏 (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
    ":"Bob
    ");
    	}
    }
    
  • 相关阅读:
    [CF1263E] Editor
    [CF1288D] Minimax Problem
    [CF1294E] Obtain a Permutation
    [CF770C] Online Courses In BSU
    [CF832D] Misha, Grisha and Underground
    [CF917B] MADMAX
    [CF938D] Buy a Ticket
    [CF959E] Mahmoud and Ehab and the xor-MST
    [CF999E] Reachability from the Capital
    [CF960F] Pathwalks
  • 原文地址:https://www.cnblogs.com/hehepig/p/6685732.html
Copyright © 2020-2023  润新知