HDU-5795 A Simple Nim(SG函数打表找规律)

题意:

两人以最优策略对n堆物品进行操作,不能操作者输.

1.从同一堆中取任意个(不为零).
2.把一堆分成任意三堆(任一堆非空).

思路:通过SG函数打表找规律,当对一堆物品进行分成三堆时,几种分法就是几种能到达的状态,而一种分法的SG值则是对该分法得到3份个数,对它们的SG值进行抑或起来就是该分法的SG值。


最终可以找到规律,SG值当对8取余为7时,SG[x] = x+1; 当对8取余为0时,SG[x] = x-1; 其余情况 SG[x] = x. 即对8的倍数位和它前一位的数值交换位置。即使各个SG值。


代码如下,

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e7+5;
int SG[maxn], mex[maxn];
void getSG(int n){
	int i, j, l;
	for(i = 1; i <= n; ++i){
		memset(mex, 0, sizeof mex);
		for(j = 1; j <= i; ++j){
			mex[SG[i-j]] = 1;
		}
		if(i >= 3){
			int r = 0;
			for(j = 1; j <= i; ++j){
				for(l = j; l <= i; ++l){
					if(i-j-l < l) break;
					r = SG[j]^SG[l]^SG[i-j-l]; 
					mex[r] = 1;
				}
			}
		}
		for(j = 0; ; ++j) if(!mex[j]) break;
		SG[i] = j;
	}
}
int main(){
	ios::sync_with_stdio(0);
	int n, x, t, i, ans;
	SG[0] = 0;
	cin >> t;
	while(t--){
		cin >> n;
		ans = 0;
		for(i = 1; i <= n; ++i){
			cin >> x;
	/*		getSG(x);
			ans ^= SG[x];
			for(int j = 0; j <= x; ++j) printf("%d ", SG[j]);
			cout << endl;*/
			if(x % 8 == 0) ans ^= x-1;
			else if(x % 8 == 7) ans ^= x+1;
			else ans ^= x; 
		}
		if(ans) cout << "First player wins." << endl;
		else cout << "Second player wins." << endl;
	}
	return 0;
} 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值