是hiho的一道姊妹题目。知道了sg定理,及其函数的计算方式后,对于本题目。
对于某一堆,每次有2个操作:
A) 要么分堆,对于状态k,分为3堆,i,j,k-i-j(i,j>0),那么状态的转移就是所有的可能分堆情况
B) 不分堆,就是普通的NIM游戏,那么状态k,可以转移到0到k-1的状态
综上,sg[k]=mex{sg[0],sg[i],sg[i] xor sg[j] xor sg[k-i-j] | i>0,j>0,k-i-j>0}
最后的答案就是每一堆的sg函数的异或和
打表找一下规律
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<map>
#include<string>
#include<set>
#include<cstdlib>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
#define LL long long
#define pb push_back
#define For(i,j,k) for(int i=(j);i<k;i++)
#define lowbit(i) (i&(-i))
#define _(x) printf("%d\n",x)
const int maxn = 15+200;
const int inf = 1 << 28;
//打表计算sg的代码
set<int> s;
int sg[maxn];
int grundy(int k){
s.clear();
sg[0]=0;
s.insert(sg[0]);
for(int i=1;i<k;i++){
for(int j=1;j+i<k;j++)
s.insert(sg[i]^(sg[j]^sg[k-i-j]));
s.insert(sg[i]);
}
int ans = 0;
while(s.count(ans))ans++;
sg[k]=ans;
return ans;
}
int main(){
/*int n=27;
for(int i=1;i<=n;i++){
printf("%2d ",i);
}
puts("");
for(int i=1;i<=n;i++){
int t = grundy(i);
printf("%2d ",t);
}*/
int T;scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
LL ans=0;
for(int i=0;i<n;i++){
LL x;scanf("%lld",&x);
if((x-7)%8==0)ans^=(x+1);
else if((x-8)%8==0)ans^=(x-1);
else ans^=x;
}
printf("%s\n",ans?"First player wins.":"Second player wins.");
}
return 0;
}