题目链接: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}} ai≤1018,很明显我们无法直接递推出所有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;
}
}