这题问了三个人才做出来,晕啊。第一位是位大牛,把基本的思路给我讲清楚了,但是在实现上卡住了,老是想着怎么开个sg[]数组记忆搜过的sg值,后来才发现想错了。第二位,之前被大牛讲明白的gbx,原来这里直接返回s - c的值当作sg值就行,至于为什么,稍后再续。第三位,zz,可以鄙视我了,因为我手贱看他的代码了,不过他的代码确实有值得学习的地方,很简练!
思路:这题明显的sg函数。可惜我纠结了半天没想起思路来。1、设当前的箱子容量为si,求出一个t满足:t + t * t < si,如果当前箱子里有ci颗石头,
1、ci > t 则必胜;
2、ci == t 则必败;
3、ci < t不能确定,将t作为si递归调用函数。
当满足ci > t时,return si - ci 作为当前状态的sg值。因为:
如图:
当ci在si点时,为有向图的端点,出度为0,也就是必败点,所以sg值为0;
当ci 位于si - 1时,ci的端点可能的sg值构成的集合为{0},所以当前sg值 为1;
当ci 位于si - 2 时,ci的端点可能的sg值构成的集合为{0, 1},所以当前的sg值为2;
。
。
。
可得,ci所在位置的sg值为si - ci;
My Code:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int sg(int c, int s){
int t = sqrt(s); //这里跟zz学的,如果s很大的话可以减少很多计算。
while(t*t + t >= s) t--;
if(c > t) return s - c;
else return sg(c, t);
}
int main(){
//freopen("data.in", "r", stdin);
int n, c, s, cas = 0, flag;
while(scanf("%d", &n), n){
printf("Case %d:\n", ++cas);
flag = 0;
while(n--){
scanf("%d%d", &s, &c);
flag ^= sg(c, s);
}
if(flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}