[UVALive - 5059] Playing With Stones 博弈论SG函数

题目链接:Playing With Stones

题意

给你n堆石子,分别有 a 1 , a 2 , a 3 , . . . . , a n {a_1,a_2,a_3,....,a_n} a1,a2,a3,....,an个。两个游戏者轮流操作,每次只能选一堆,拿走至少一个石子,但不能拿走超过一半的石子。问先手是否能获胜。

题解

本题比Nim游戏多了一个条件,“每次不能拿走超过一半的石子”,并且 a i ≤ 1 0 18 {a_i≤10^{18}} ai1018,很明显我们无法直接递推出所有SG函数,但可以先打表看看。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);


int sg[maxn];
int vis[maxn];

int main()
{
    
    
	sg[1]=0;
	for(int i=2;i<=30;i++)
	{
    
    
		memset(vis,0,sizeof(vis));
		for(int j=1;j*2<=i;j++) vis[sg[i-j]]=1;
		for(int j=0;;j++)
			if(!vis[j])
			{
    
    
				sg[i]=j;
				break;
			}
		printf("%d ",sg[i]);
	}
}

SG函数结果:
1 0 2 1 3 0 4 2 5 1 6 3 7 0 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15 (从2开始)
发现偶数位为:1,2,3…
SG(n)=n/2 (n%2==0)
我们把偶数位去掉,会得到一个新数列:0,1,0,2,1,3…和原数列一样!!!
可通过递归求解得:SG(n)=SG(n/2)

这样我们找到了SG函数规律,直接求解即可。
用SG定理:游戏和的SG函数等于各个子游戏SG函数的Nim和。得到答案。

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);


ll sg(ll x) {
    
     return x%2==0?x/2:sg(x/2); }

int main()
{
    
    
	int t; cin >> t;
	while(t--)
	{
    
    
		int n; cin >> n;
		ll ans=0;
		for(int i=1;i<=n;i++)
		{
    
    
			ll tmp; cin >> tmp;
			ans ^= sg(tmp);
		}
		if(ans==0) cout << "NO" << endl;
		else cout << "YES" << endl;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_44235989/article/details/108217766