uoj#51[UR #4]元旦三侠的游戏 博弈论+dp

Posted GXZlegend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uoj#51[UR #4]元旦三侠的游戏 博弈论+dp相关的知识,希望对你有一定的参考价值。

题目描述

给出 $n$ 和 $m$ ,$m$ 次询问。每次询问给出 $a$ 和 $b$ ,两人轮流选择:将 $a$ 加一或者将 $b$ 加一,但必须保证 $a^b\le n$ ,无法操作者输,问先手是否必胜。

$n\le 10^9$ ,$m\le 10^5$ ,$a\ge 2$ ,$b\ge 1$ ,$a^b\le n$


题解

博弈论+dp

显然可以想到预处理 $f[i][j]$ 表示 $a$ 为 $i$ ,$b$ 为 $j$ 时先手能否胜利。显然由 $f[i+1][j]$ 和 $f[i][j+1]$ 推出。

但是由于 $n$ 有 $10^9$ 就会GG...

我们考虑:当 $i^j\le n$ 且 $i^{j+1}>n$ 时,先手只能选择将 $a$ 加一,后手也一样。因此胜负已定。

因此当 $b=1$ 时可以只预处理到 $f[\sqrt n][1]$ ,当 $a>\sqrt n$ 时显然可以 $O(1)$ 判断。

时间复杂度 $O(m+\sqrt n\log n)$ 。

其实对于每一个 $b$ 都可以用同样的方法判断,时间复杂度变为 $O(m+\sum\limits_{i=2}^{\log n}\sqrt[i]{n})=O(m+\sqrt n)$ 但没什么必要。。。

#include <cstdio>
int p[32010][31] , log[32010] , f[32010][31]; //0: win
int main()
{
	int n , m , i , j , a , b;
	scanf("%d%d" , &n , &m);
	for(i = 2 ; i <= 32000 ; i ++ )
	{
		if(i > n) log[i] = 0;
		else
		{
			p[i][1] = i;
			for(j = 2 ; 1ll * p[i][j - 1] * i <= n ; j ++ )
				p[i][j] = p[i][j - 1] * i;
			log[i] = j - 1;
		}
	}
	f[32001][1] = !((n - 32001) & 1);
	for(i = 32000 ; i != 1 ; i -- )
		for(j = log[i] ; j ; j -- )
			f[i][j] = !(f[i][j + 1] || f[i + 1][j]);
	while(m -- )
	{
		scanf("%d%d" , &a , &b);
		puts((a > 32000 ? !((n - a) & 1) : f[a][b]) ? "No" : "Yes");
	}
	return 0;
}

 

以上是关于uoj#51[UR #4]元旦三侠的游戏 博弈论+dp的主要内容,如果未能解决你的问题,请参考以下文章

UOJ#52. UR #4元旦激光炮(交互)

uoj#266. 清华集训2016Alice和Bob又在玩游戏(博弈论)

UR #4元旦激光炮

UOJ#53. UR #4追击圣诞老人 树链剖分 k短路

51nod 1831 小C的游戏(博弈论+打表)

uoj167 元旦老人与汉诺塔(记忆化搜索)