题意:给定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。然后异或下就出来结果了。
打表:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn=1e4+10; int sg[maxn],vis[maxn]; void solve() { 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() { solve(); }
AC:
#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 "); else printf("Alice "); } return 0; }