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;
}