题意:n堆石子,每次从一堆取若干个,或者把一堆分成非空的三堆(这时不能取)。
求sg,如果一堆有x个,那么对取来说它能转移到的状态为0,1,2,.... x-1 ,如果分三堆,可以类比剪纸的博弈游戏(poj 2311 http://poj.org/problem?id=2311),只要对分成的三部分取异或,就代表x所能转移到的下一状态。 然后打表找规律就可以了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const ll inf=1e9;
const ll mod=1e9+7;
//map<int,int> vis;
int main()
{
//for(int i=0;i<)
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
int x;
int ans=0;
for(int i=0;i<n;i++){
scanf("%d",&x);
if(x%8==0)x--;
else if( (x+1)%8==0 )x++;
ans=ans^x;
}
if(n==1){
puts("First player wins.");
}
else if(ans==0){
puts("Second player wins.");
}
else
{
puts("First player wins.");
}
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const int maxn=1000+5;
const ll inf=1e9;
const ll mod=1e9+7;
set<int> ::iterator it;
int a[maxn];
int sg[maxn];
int grundy(int x){
if(sg[x]>=0)return sg[x];
set<int>s;
for(int i=1;i<=x;i++){
s.insert(grundy(x-i));
}
for(int i=1;i<=x;i++){
for(int j=i;j<=x;j++){
for(int k=j;k<=x;k++){
if(i+j+k==x){
s.insert(grundy(i)^grundy(j)^grundy(k));
}
}
}
}
int g=0;
while(s.count(g)!=0)g++;
sg[x]=g;
return g;
}
int main()
{
memset(sg,-1,sizeof(sg));
sg[0]=0;
for(int i=1;i<=100;i++){
printf(" i==%d sg==%d ",i,grundy(i));
if(i%5==0)printf("\n");
}
return 0;
}