大致思路:
其实这之前(https://blog.csdn.net/m0_38033475/article/details/80281556)差不多,也是列写sg值对于不同情况时是多少,之前只觉得c==s则sg==0,但忘了考虑若c==t-1,则sg也为0!我的错因就是在于没有牢牢结合题意操作!因为如果你是t-1了,你按照题意的后续操作最多也就s-1(但好像(t-1)*(t-1)+t到不了s-1),那么你的sg肯定为0啊!也可以这样想:你是t-1了,你至少加1,不管咋加也到不了s,但不管你咋加,下一轮人家都可以一次加到s,那么你先手必输,sg=0没毛病。
那么这样的话,思路很明了了。首先需要找到题解里那个t值,然后需要比较c和t。如果s<t,那么返回递归sg(t-1,c)。你看表就知道为啥要递归了!!!!
AC代码(二分法我竟然忘了怎么写。。。。。而且二分法我之前还写成递归了,md运行超时啊我倒!):
#include<iostream> #include<bits/stdc++.h> using namespace std; int n; int erfen(int l,int r,int t) //二分法 l下界 r上界 t最大容量 { long long ans=0; while(l<=r) { long long mid=(l+r)/2; //这里要给longlong,不然mid*mid也是int型但数值容易超过int导致错误 if(mid*mid+mid>=t) //这里不要写成==,因为有可能并不存在==的情况!只要一直这样找找到最后即ans为最接近值! { ans=mid; r=mid-1; } else if(mid*mid+mid<t) l=mid+1; } return ans; } int getsg(int t,int c) //经过考虑 应该用递归单次求sg(不然那么大数据去打表?). t最大容量 c当前数量 { if(t==c) return 0; int m=erfen(1,t,t); //二分法去查找那个影响输赢的临界值 if(t==m-1) return 0; if(c>=m) return t-c; else return getsg(m-1,c); } int main() { cin>>n; int ans=0; //求异或和,初始值设为0! for(int i=1;i<=n;i++) { int t,c; scanf("%d%d",&t,&c); ans^=getsg(t,c); } if(ans==0) cout<<"No"; else cout<<"Yes"; return 0; }