1. 程式人生 > >HDU 3032(Multi-SG函式)

HDU 3032(Multi-SG函式)

傳送門

Nim is a two-player mathematic game of strategy in which players take turns removing objects from distinct heaps. On each turn, a player must remove at least one object, and may remove any number of objects provided they all come from the same heap. 

Nim is usually played as a misere game, in which the player to take the last object loses. Nim can also be played as a normal play game, which means that the person who makes the last move (i.e., who takes the last object) wins. This is called normal play because most games follow this convention, even though Nim usually does not. 

Alice and Bob is tired of playing Nim under the standard rule, so they make a difference by also allowing the player to separate one of the heaps into two smaller ones. That is, each turn the player may either remove any number of objects from a heap or separate a heap into two smaller ones, and the one who takes the last object wins.

Input

Input contains multiple test cases. The first line is an integer 1 ≤ T ≤ 100, the number of test cases. Each case begins with an integer N, indicating the number of the heaps, the next line contains N integers s[0], s[1], ...., s[N-1], representing heaps with s[0], s[1], ..., s[N-1] objects respectively.(1 ≤ N ≤ 10^6, 1 ≤ S[i] ≤ 2^31 - 1)

Output

For each test case, output a line which contains either "Alice" or "Bob", which is the winner of this game. Alice will play first. You may asume they never make mistakes.

Sample Input

2
3
2 2 3
2
3 3

Sample Output

Alice
Bob

題意:

    給定你n堆石子,每次可以取走任意數量個,或者將一堆式子拆分成兩堆(事實上更多也是可行的)非空石子,不能操作者輸,判定勝負。

題目分析:

    這是一個經典的Multi-SG遊戲的問題。

    相較於普通的Nim遊戲,該遊戲僅僅是多了拆成兩堆這樣的一個狀態。即多了一個SG(x+y)的過程。

    而根據SG定理,SG(x+y)這個遊戲的結果可以拆成SG(x)和 SG(y)遊戲的結果的xor。

    因此,在我們求SG函式的過程中,我們只需要再列舉一下拆成兩堆的狀態,即可獲得Multi-SG遊戲每個狀態的SG函式。

    但是題目中的資料範圍較大(達到了1e5的級別),因此我們考慮先打表找規律。打出SG函式後不難發現,存在規律:

    順著上面的規律即可求出每一個狀態的SG函式,最後將這些SG函式結果全都xor起來即可。

程式碼:

#include <bits/stdc++.h>
#define maxn 105
using namespace std;
int vis[maxn];
int sg[maxn];
void init(){//SG函式打表
    for(int i=0;i<100;i++){//列舉100個狀態
        memset(vis,0,sizeof(vis));
        for(int j=1;j<=i;j++){
            vis[sg[i-j]]=true;
        }
        for(int j=1;j<i;j++){//列舉分成兩塊的狀態
            vis[sg[j]^sg[i-j]]=true;
        }
        for(int j=0;;j++){
            if(!vis[j]){
                sg[i]=j;
                break;
            }
        }
    }
    for(int i=0;i<100;i++){
        cout<<i<<" "<<sg[i]<<endl;
    }
}
int SG(int n){
    if(n%4==1||n%4==2) return n;
    else if(n%4==3) return n+1;
    else return n-1;
}
int main()
{
    //init();
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        int res=0;
        for(int i=0;i<n;i++){
            int num;
            scanf("%d",&num);
            res^=SG(num);
        }
        if(res) puts("Alice");
        else puts("Bob");
    }
    return 0;
}