【博弈SG】蒜头君的新游戏


大致思路

其实这之前(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;
} 




猜你喜欢

转载自blog.csdn.net/m0_38033475/article/details/80292754
今日推荐