Alice Game hdu7287

Problem - 7287

题目大意:有n个石子放在一堆,每次操作可以选择拿走k个石子,然后将那一堆剩下的分成两堆,新堆不能为空,如果某一堆石子数小于等于k,可以直接拿完那一堆,不能操作的人输掉,A先B后问谁能赢

2<=k<=1e7;0<=n<=1e9

思路:我们先讨论k确定的情况,n=0时,先手不能操作,sg[0]=0,n=1~k时,都只能转移到0,sg[1]=1,n=k+1时,不能转移到其他位置,sg[k+1]=0,在n>k+1时,就需要讨论分堆的情况,从1到n枚举分出的其中一堆的石子数量i,另一堆的数量j即为x-k-i(x为当前枚举的石子数量),如果j>0,那么这时就分成了两个子游戏,所以sg[x]=sg[i]^sg[j],我们照此计算出k=2,3,4时先手必败也就是sg[i]=0的情况,发现除了sg[k+1]=0以外,之后n每增加4k+2,sg[n]都等于0,所以我们得出结论当(n-(k+1))%(4k+2)=0时先手必输,否则先手必胜

//#include<__msvc_all_public_headers.hpp>
#include
using namespace std;
//int k;
//typedef long long ll;
//ll sg[1005];
//ll f(ll x)
//{//递归计算sg值
//	if (sg[x] != -1)
//	{//记忆化搜索
//		return sg[x];
//	}
//	sets;
//	for (int i = 1; i <= x; i++)
//	{//分堆
//		int j = x - i - k;
//		if (j <= 0)
//			continue;
//		s.insert(sg[i] ^ sg[j]);
//	}
//	int now = 0;
//	while (s.count(now))
//	{//找MEX
//		now++;
//	}
//	return now;
//}
//int main()
//{
//	ios::sync_with_stdio(false);
//	cin.tie(0);
//	cout.tie(0);
//	cin >> k;
//	memset(sg, -1, sizeof sg);
//	sg[0] = 0;
//	for (int i = 1; i <= k; i++)
//	{
//		sg[i] = 1;
//	}
//	for (int i = k + 1; i <= 1000; i++)
//	{
//		sg[i] = f(i);
//	}
//	for (int i = 1; i <= 1000; i++)
//	{
//		if (!sg[i])
//		{
//			cout << i << " " << sg[i] << endl;
//		}
//	}
//	return 0;
//}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		int k, n;
		cin >> k >> n;
		if ((n - k - 1) % (4 * k + 2) == 0)
		{
			cout << "Bob" << endl;
		}
		else
			cout << "Alice" << endl;
	}
}

你可能感兴趣的:(博弈论,算法,c++)