Nim or not Nim? HDU - 3032(尼姆博奕变形)

Nim or not Nim?

HDU - 3032
题意是这样的:尼姆博弈游戏在原有的游戏规则上附加一条——玩家除了取石子操作外,还可以将一堆石子分成两份,这也算一次操作;
想一下,之前的尼姆博奕是在一堆石子中取任意个石子,判断条件是每堆石子个数异或运算,结果为0则先手必败,反之,先手必胜;
现在可以将石子堆分解了;
还记得尼姆博奕是怎么算的吗?异或,每堆石子个数异或表示的什么?其实每堆石子个数就是这堆石子的SG值,所以本质上尼姆博奕是每堆石子的SG值异或运算;所以只需要求出现在的每堆石子SG值再进行异或运算;
SG怎么算?
原始版本的SG是这样算的:SG[x]=mex(SG[y]|y是x的后续(通俗的讲,y是x可以一步到达的状态));mex()函数是求集合中未出现的最小非负整数;如mex(0,2,3)=1;
现在这个题SG也是这样求,只不过其中的y有点变化;
SG[0]=0;
SG[1]=mex(SG[0])=mex(0)=1;
SG[2]=mex(SG[0], SG[1], SG[1]^SG[1])=mex(0,1,1)=2;//是不是有点奇怪SG[1]^SG[1]的来历?石子堆是可以再分的,2就分成了1,1,不就是SG[1]^SG[1]了么;
SG[3]=mex(SG[0], SG[1], SG[2], SG[1]^SG[2])=mex(0, 1, 2, 3)=4;
SG[4]=mex(SG[0], SG[1], SG[2], SG[3], SG[1]^SG[3], SG[2]^SG[2])=mex(0, 1, 2, 4, 2, 0)=3;
......
根据打表得
n%4==0时:SG[n]=n-1,    
n%4==3时:SG[n]=n+1,
其他情况    :SG[n]=n;
然后对求出的吗,每堆石子的SG值进行异或就可以了;
打表打上个几十个一般就能看出明显的规律了;
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
int sg[1000];
int vis[1000];
/*
打表求SG的函数: 
int cal(int x){
	if(x==0) return 0;
	if(x==1) return 1;
	int temp=0;
	memset(vis, 0, sizeof(vis));
	for(int i=0; i<x; i++){
		vis[sg[i]]=1;
	}
	for(int i=1; i<x; i++){
	vis[sg[i]^sg[x-i]]=1;
	}
	for(int i=0; i<1000; i++){
		if(vis[i]==0){
			return i;
		}
	}
}
*/
int s[1000010];
int main(){
	int T;
	cin >> T;
	while(T--){
		int n, x;
		scanf("%d", &n); 
		for(int i=0; i<n; i++){
			scanf("%d", &x);
			if(x%4==3) sg[i]=x+1;
			else if(x%4==0) sg[i]=x-1;
			else sg[i]=x;
		}
		int temp=0;
		for(int i=0; i<n; i++){
			temp=temp^sg[i];
		}
		if(temp) printf("Alice\n");
		else printf("Bob\n"); 
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/80437280
Nim
今日推荐