题意:给定n堆石子,两人轮流操作,每次选一堆石子,取任意石子或则将石子分成两个更小的堆(非0),取得最后一个石子的为胜。
题解:比较裸的SG定理,用sg定理打表,得到表1,2,4,3,5,6,8,7,9,10,12,11...可以发现当x%4==0时sg[x]=x-1;当x%4==3时sg[x]=x+1;其余sg[x]=x。然后异或下就出来结果了。主要还是用学会SG定理。详细的可以百度,或则看我其他的文章(我自己都忘了哪篇写过。。)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int find(int x)
{
if(x%4==0)return x-1;
else if(x%4==3)return x+1;
return x;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int a,n,i,j,ans=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&a);
ans=ans^find(a);
}
if(ans==0)printf("Bob\n");
else printf("Alice\n");
}
return 0;
}
SG定理打表+找规律:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e4+10;
int sg[maxn],vis[maxn];
void init()
{
int i,j,k;
sg[0]=0,sg[1]=1;
for(i=2;i<=1000;i++)
{
memset(vis,0,sizeof(vis));
for(j=1;j<i;j++)
vis[sg[j]^sg[i-j]]=1; //拆分
for(j=0;j<i;j++)
vis[sg[j]]=1; //取石子
for(j=0;;j++)
if(!vis[j])break;
sg[i]=j;
}
for(i=1;i<=20;i++)
cout<<sg[i]<<endl;
}
int main()
{
init();
}