Stone Game
题意:
给定n个箱子,每个箱子的容量为si,每个箱子里最初有ci个石子,每次放入石子不能超过放入前的石子数的平方,谁无法继续放入石子就算输。
/* 这是个SG函数的基础题?并不是的吧。。 求一个t使t+t*t=si,那么 1.当ci>t时,是必胜态,可以一次性放满箱子,即(si,si)。 2.当ci==t时,即便只放一个,下一个状态t+1+(t+1)*(t+1)一定能放满箱子必胜,所以ci==t这个状态必败。 3.当ci=si-t,同样的方法判断必胜必败,这样就可以通过递归求解sg值。 求sg:要得到sg需要对他的子集做mex{}运算,求出不属于该集合的最小非负整数。 在ci>t时满足 对于ci==si这个点,ci在有向图中没有出度(必败),因此返回si-ci=0,; 在ci==si-1时,它能到达的只有si点,sg[ci]={sg[si]=0},所以sg[ci]=1. 在ci==si-2时,他能到达的点有si-1,si,所以sg[ci]={sg[si-1]=1,sg[si]=0},所以sg[ci]=2. 因此在ci>t时返回si-ci 在ci==t是是必败,可直接返回0,也可以不做判断直接进入下一轮递归。 */ #include<iostream> #include<cstdio> #include<cmath> #define maxn 51 using namespace std; int n; int getSG(int s,int c){ int t=sqrt(s); while(t*t+t>=s)t--; if(c>t)return s-c; if(c==t)return 0; return getSG(t,c); } int main(){ int cas=0; while(scanf("%d",&n)){ cas++; if(n==0)return 0; printf("Case %d:\n",cas); int ans=0,s,c; for(int i=1;i<=n;i++){ scanf("%d%d",&s,&c); ans^=getSG(s,c); } if(ans)puts("Yes"); else puts("No"); } }