这个题目属于比较难的博弈,解决的方式的,通过一些预处理,转化成Nimm博弈。
首先,只考虑单个箱子的胜负。假设该箱子能放s个石头,已经有c个石头,状态为(s,c),当先手的人使状态变成(s,s)时,那么他就赢了。
我们假设先手者是通过一步操作,达到(s,s)的,假设放进了k个石头,那么,由于条件限制,就有
c+k=s;
1<=k<=c*c;
假设k的起点是t+1,也就是说:
t+t*t<s;
(t+1)+(t+1)*t(t+1)>=s;
此处的t+1点,既是必胜点,因为可以通过一步操作,构造出(s,s)的状态给对手。
而t点,则是必胜点,因为它无法一步取胜,但不管它做什么操作,都会试对手轻而易举地构造出(s,s)
那么,可以推导:
当c>t点的时候,先手是胜的;
当c=t点的时候,先手是输的;
当c<t的情况,是不知道的,但是,(t,t)是必负态,那么它的功效和(s,s)是等同的,问题转化成(t,c);
最后,返回s-c,作为Nimm博弈的起始值,通过异或操作,判断出胜负。
/*
HDOJ1792
作者:陈佳润
2013-04-07
*/
#include<iostream>
#include<math.h>
using namespace std;
int sg(int s,int c){
int t=(int)sqrt(double(s));
while(t+t*t>=s)
t--;
// why 不能c>=t; 此处有限制,如果加上等于号,那么,返回了一堆物品的取物是带限制的,而转化成nimm博弈不能有限制,所以不能等于
if(c>t)
return s-c;
else
return sg(t,c);
}
int main(){
int Case=0,ans,n,s,c;
while(scanf("%d",&n)!=EOF&&n){
Case++;
ans=0;
while(n--){
scanf("%d%d",&s,&c);
ans=ans^sg(s,c);//转化成Nimm博弈
}
if(ans)
printf("Case %d:\nYes\n",Case);
else
printf("Case %d:\nNo\n",Case);
}
return 0;
}