HDU3032 Nim or not Nim?(博弈/Multi-SG游戏)

Problem Description

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

Multi-SG游戏模版(可以将一堆石子分成多堆,此题为两堆)。求解方法是先打表找规律,然后直接异或判断。

详细证明:HDU3032_NimOrNotNim解题报告_weixin_30865427的博客-CSDN博客

打表代码及ac代码如下:

#include <bits/stdc++.h>
#define N 5005
using namespace std;
int n, a[1000005];
int sg[100005];
bool vis[100005];
void dabiao() {
	sg[0] = 0, sg[1] = 1;
	for(int i = 1; i < N; i++) {
		memset(vis, 0, sizeof(vis));
		//操作1:至少取一个 最多全取走
		for(int j = 1; j <= i; j++) {vis[sg[i - j]] = 1;}
		//注意这里要取等
		//操作2:分成两堆,因为一堆不能为空所以不能取等
		//将一堆石子分成两堆,等于将一个一堆的Nim游戏A变成两个一堆游戏的和B,这两个一堆游戏之和也是A的后继状态。计算A的SG函数时,除了考虑普通后继状态之外,还要将B的SG值加入mex计算,而B的SG值是两个成员游戏SG值的异或◎(根据和游戏定理)。
		for(int j = 1; j < i; j++) {vis[sg[j] ^ sg[i - j]] = 1;}
		for(int k = 0; k < N; k++) {//mex操作 该状态的 SG 函数值即为后继状态的 SG 函数值中未出现过的最小值
			if(!vis[k]) {
				sg[i] = k;
				break;
			}
		}
		cout << sg[i] << endl;
	}
}
int getSG(int x) {
	if(x % 4 == 0) return x - 1;
	else if(x % 4 == 3) return x + 1;
	else return x;
}
int main() { 
	int t;
	cin >> t;
	while(t--) {
		cin >> n;
		int x = 0;
		for(int i = 1; i <= n; i++) {
			int tmp;
			cin >> tmp;
			x ^= getSG(tmp);
		}
		if(x) cout << "Alice" << endl;
		else cout << "Bob" << endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lipoicyclic/p/14730644.html