HDU 3404 Switch lights (NIM 积)

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3404

选出一个矩形,改变四个角灯的状态,而且右下角的灯初始必须是开的。

这类组合博弈问题在 神牛曹钦翔的论文:从“k倍动态减法游戏”出发探究一类组合游戏问题“有说到。

如果只有一行,即n=0,每一枚向上硬币可以被理解成一个单独的游戏,于是游戏似乎就变成这些单独游戏的“和”,因为翻两枚硬币可以理解成把“坐标大”的正面硬币移到了坐标小的位置。唯一一点区别是,同时翻两枚正面向上的硬币,就相当于坐标小的被坐标大的硬币“消掉”了。这其实与游戏“和”模型是不矛盾的,因为两个相同位置的正面硬币的SG 函数值必相同,因此他们的Nim 和为0,所以等于“没有”。
回到原来问题,显然问题也归结为若干个单独游戏的和——若干个单独的证面向上的硬币。在只包含一行的游戏中,一颗正面向上的硬币的SG 函数就是它的列坐标。

每枚正面向上的硬币可以理解成一个独立的简单游戏,而在这个游戏中,每次操作能加一个简单游戏拆分成3 个游戏的“和”。这是游戏“和”的嵌套。

这是这个题目的分析,具体的NIM积的运算以及性质 在论文里面也有详解,请参考

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2000000
using namespace std;
int m[2][2]={0,0,0,1};
int Nim_Mult_Power(int x,int y){
	if(x<2)
		return m[x][y];
	int a=0;
	for(;;a++)
		if(x>=(1<<(1<<a))&&x<(1<<(1<<(a+1))))
			break;
	int m=1<<(1<<a);
	int p=x/m,s=y/m,t=y%m;
	int d1=Nim_Mult_Power(p,s);
	int d2=Nim_Mult_Power(p,t);
	return (m*(d1^d2))^Nim_Mult_Power(m/2,d1);
}
int Nim_Mult(int x,int y){
	if(x<y)
		return Nim_Mult(y,x);
	if(x<2)
		return m[x][y];
	int a=0;
	for(;;a++)
		if(x>=(1<<(1<<a))&&x<(1<<(1<<(a+1))))
			break;
	int m=1<<(1<<a);
	int p=x/m,q=x%m,s=y/m,t=y%m;
	int c1=Nim_Mult(p,s),c2=Nim_Mult(p,t)^Nim_Mult(q,s),c3=Nim_Mult(q,t);
	return (m*(c1^c2))^c3^Nim_Mult_Power(m/2,c1);
}
int main(){
	int t,n,x,y;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		int ret=0;
		while(n--){
			scanf("%d%d",&x,&y);
			ret^=Nim_Mult(x,y);
		}
		if(ret)
			puts("Have a try, lxhgww.");
		else
			puts("Don't waste your time.");
	}
	return 0;
}


你可能感兴趣的:(游戏,c)