题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1729
看了题目感觉像Nim,但是有范围限制,有点不知道SG函数该怎么写
看了题解,最后才明白该怎么去理解 。
首先进行对s和c进行分类,
1、c = 0 的时候,无论怎样都填不满,直接跳过;
2、c = s 的时候,先手必败,即是P态;
3、c < s 的时候,可以分为两种情况:
1)c^2 + c < s 的时候,递归
2)c^2 + c > s 的时候,先手必胜,即N态
1 int mex(int s, int c){ 2 if( c == 0 || s == c) 3 return 0; 4 int q = sqrt(s); 5 while( q+q*q >= s) 6 q--;//最大的不能一次填满的数 7 if(c > q) return s-c; 8 else return mex(q,c); 9 }
主要的理解难点就是 mex(s,c)和mex(k,c)为什么是等价的,个人是这么理解的,
当跑到第一个q+q*q<s的时候,如果c>q,那么可以一次填满,
但如果c<q,不可能一次填满,此时可以分割成两个事件,mex(c,k)和mex(s,k),
其中对于mex(s,k),mex(s,s) 是先手必败,即P态,mex(s,k+1)...mex(s,s-1)都是先手必胜,即N态,
所有移动都导致N态局面的是P态,所以显然mex(s,k)是P态,那么mex(s,k)显然与mex(k,c)等价
1 #include<stdio.h> 2 #include<cmath> 3 #include<cstring> 4 using namespace std; 5 const int MAXN = 1000010; 6 int mex(int s, int c){ 7 if( c == 0 || s == c) 8 return 0; 9 int q = sqrt(s); 10 while( q+q*q >= s) 11 q--;//最大的不能一次填满的数 12 if(c > q) return s-c; 13 else return mex(q,c); 14 } 15 int main(){ 16 int N; 17 int ans; 18 int s, c; 19 int T = 0; 20 while(~scanf("%d",&N)&&N){ 21 ans = 0; 22 for(int i = 0; i < N; ++i){ 23 scanf("%d%d",&s,&c); 24 ans = ans^mex(s,c); 25 } 26 printf("Case %d:\n",++T); 27 if(ans) 28 puts("Yes"); 29 else 30 puts("No"); 31 } 32 }
时间: 2024-12-28 10:59:09