2021牛客多校1 A

2021牛客多校1 A

题目链接

题意:

两人博弈,两堆石子,每次操作从一堆中取 k 个,另一堆中取 k * s 个,谁先没得取谁输, N <= 5000。

思路:

结论:
当一堆石子数量为 i 时,要想后手取胜,第二堆石子仅有一种可能。
反证法:
假设(i,q)和(i,p)都是后手获胜,且 q > p,则当面临(i,q)局面时,先手可以取走 q - p 个石子使局面变为(i,p)且为后手,此时必胜,与前提矛盾。
然后开始暴力
数组 f[i][j] = 1 表示一堆石子为 i ,另一堆为 j 时,先手必胜。
可以看出,f[0][0] = 0。
因此从(0,0)开始,枚举两堆石子的个数,若 f[i][j] = 0 ,则 f[i + k][j + s * k] = f[i + s * k][j + k] = 1
显然,暴力时间复杂度为 O ( n 4 ) O(n^4) O(n4) 会超时,但是由结论可知,对于每个 i ,任意的 j 构成的局面,至多有一种先手必败态(即后手必胜),因此复杂度可减低至大约 O ( n 3 ) O(n^3) O(n3) ,加上奇奇怪怪的小优化,850ms跑过…

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<math.h>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double dd;
typedef pair<int, int> pii;
typedef pair<dd, dd> pdd;
const int MAXN = 5001; //这里开成 5010 会T,非常神秘
const int inf = 1e9 + 7;
const ll llinf = 1e17 + 7;
const int MAXM = 5005000;

bool f[MAXN][MAXN];//开成 int 会T,非常神秘×2

int main()
{
	for (int i = 0;i <= 5000;i++)
	{
		for (int j = 0;j <= 5000;j++)
		{
			if (!f[i][j])
			{
				for (int k = 1;k + i <= 5000;k++)
				{
					for (int s = 0;s * k + j <= 5000;s++)
					{
						f[i + k][j + s * k] = 1;
					}
				}
				for (int k = 1;k + j <= 5000;k++)
				{
					for (int s = 0;s * k + i <= 5000;s++)
					{
						f[i + s * k][j + k] = 1;
					}
				}
			}
		}
	}
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		if (f[n][m] == 1) puts("Alice");
		else puts("Bob");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值