[UOJ Round#4 A] [#51] 元旦三侠的游戏

题目链接:UOJ - 51

据说这题与 CF 39E 类似。

题目分析

一看题目描述,啊,博弈论,不会!等待爆零吧...

这时,XCJ神犇拯救了我,他说,这题可以直接搜啊。

注意!是用记忆化搜索,状态为 (a, b) 。

是这样的:我们从后面倒着推,对于一个无法再增加 a 或 b 的 (a, b) 状态,当前走的人必败。这是终止的状态。

而对于一个不是终止状态的状态 (a, b) ,可能有两种后继状态 (a + 1, b) || (a, b + 1) ,我们递归先求出这两个后继状态是必败还是必胜。

如果两个后继状态中有一个是必败的,那么就存在走法使得下一个走的人必败,那么一定会走那个状态(因为所有人都足够聪明),当前状态就是必胜的。

否则,无论怎么选择,下一个走的人都必胜,那么当前状态就是必败的。

注意,如果某一个后继状态不合法,那么就当作一个必胜状态吧,因为当前不能那样走。

需要注意的是,当 b = 1,合法的 a 有 n 个,是不能搜完也不能存储的,我们把 b = 1 的状态分为两类:

1) a <= sqrt(n) 这种状态下,b 可能会增加, 所以和别的状态一样处理。

2) a > sqrt(n) 这样的状态,b是不能增加的,直接看 n - a 的奇偶就好了。每次用到这种状态的时候就单独做一下。

这样能求出所有可行状态的必胜或必败属性,由于对于每个 b ,可行 a 的个数差别过大,我们对每个 b 用一个 vector 存所有可行 a 的答案 (STL就是好!)。

对于每一个查询直接输出就好了。

特别注意的是!一定要记忆化搜索啊!不记忆化就TLE到爆啊!!状态重复搜了太多太多次啊!!

写代码时出现的错误:这样判断了后继状态 if (DFS(x + 1, y) && DFS(x, y + 1)) 这样是万万不可以的!!后面的一个 DFS(x, y+1) 放在了&& 之后,只要前面的值为 true ,后面的这个 DFS 直接就不调用了!!就跪了!!

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

const int MaxN = 1000000 + 5;

int n, m, a, b, SqrtN, Top;

vector<int> E[35];

typedef long long LL;

bool Pow(int a, int b) {
	LL f, ret;
	f = a; ret = 1ll;
	while (b) {
		if (b & 1) {
			ret *= f;
			if (ret > n) return true;
		}
		b >>= 1;
		f *= f;
	}
	if (ret > n) return true;
	return false;
}

bool DFS(int x, int y) {
	if (y != 1 && (int)E[y].size() > x && E[y][x] != 0) return (E[y][x] == 1);
	if (Pow(x, y)) return true;
	if (y == 1 && x > SqrtN) {
		if ((n - x) & 1) return true;
		else return false;
	}
	bool Flag1, Flag2;
	Flag1 = DFS(x + 1, y);
	Flag2 = DFS(x, y + 1);
	while ((int)E[y].size() <= x) E[y].push_back(0);
	if (Flag1 && Flag2) {
		E[y][x] = -1;
		return false;
	}
	else {
		E[y][x] = 1;
		return true;
	}
}

bool WillWin(int x, int y) {
	if (y == 1 && x > SqrtN) {
		if ((n - x) & 1) return true;
		else return false;
	}
	return (E[y][x] == 1);
}

int main()
{
	scanf("%d%d", &n, &m);
	SqrtN = (int)sqrt(n * 1.0);
	DFS(2, 1);
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &a, &b);
		if (WillWin(a, b)) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

  

时间: 2024-08-25 22:33:39

[UOJ Round#4 A] [#51] 元旦三侠的游戏的相关文章

【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+

【UOJ Round #1】

枚举/DP+排列组合 缩进优化 QAQ我当时一直在想:$min\{ \sum_{i=1}^n (\lfloor\frac{a[i]}{x}\rfloor + a[i] \ mod\ x) \}$ 然而并不会做啊……一点思路也没有……主要是后面那个取模非常难受…… 其实正解有点逆向思维的感觉:$ans=\sum_{i=1}^n a[i] - max\{ \sum_{i=1}^n \lfloor \frac{a[i]}{x}\rfloor *(x-1) \} $ 也就是先将a[i]全部加起来,然后再

【UOJ Round #8】

A 一道不错的题,虽然大家都觉得是水题,然而蒟蒻我想出来的好慢……Orz alpq 发现其实就是一个网格图,每一个大块都是同一颜色……横纵坐标互不干扰…… 1 //UOJ Round #8 A 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<iostream> 7 #include<algorithm> 8

【Unity 3D】学习笔记三十三:游戏元素——天空盒子

天空盒子 一般的3D游戏都会有着北京百年一遇的蓝天,让人惊叹不已.其实天空这个效果没有什么神秘的只需用到天空盒子这个组件就行,可以将天空设想成一个巨大的盒子,这个盒子将整个游戏视图和所有的游戏元素包含其中.在unity中制作天空盒子非常方便,只需要像设置其他组件一样设置下就行了.在制作天空盒子之前,我们需要搜集一些天空的贴图,不过,unity很方便的为开发者提供了天空盒子的资源包.首先在project视图中点击鼠标右键,然后选择import package--skyboxes即可添加天空盒子的资

【Unity 3D】学习笔记三十一:游戏元素——地形元素

地形元素 一般情况下,为了使游戏更具有美观性,会在游戏地形上放置很多的元素,这些元素是与地形分开的.主要包括:树木,草地,自定义网格模型. 树元素 首先导入系统提供的树木标准资源包,在project视图中,点击鼠标右键,然后从菜单中选择import-----tree creator.接着在地形菜单里点击第五个按钮,添加树模型.然后点击edit trees按钮,将弹出如下列表: add tree:添加一个树模型 edit tree:编辑一个树模型 remove tree:删除树模型 点击add t

JavaFX战旗类游戏开发 第三课 创建游戏角色

在上一节课程中,我们学习了在JavaFX中绘制游戏地图.这一节课,我们将会创建我们的游戏角色. 首先,同样的,我们创建一个简单的基类. import javafx.scene.canvas.GraphicsContext; /** * 游戏物体基类 * @author Wing Mei */ public abstract class BaseObject { protected double x, y; protected double width,height; protected bool

(转)CocosCreator零基础制作游戏《极限跳跃》三、制作游戏主场景

CocosCreator零基础制作游戏<极限跳跃>三.制作游戏主场景 刚刚我们制作了游戏的开始场景,现在我们来制作游戏的主场景.还是同样的方法,新建一个名为MainScene的场景,双击打开,修改场景的大小为480x800. 1.首先贴入游戏背景,在此我们使用了2张背景图,只需要把背景拖进层级管理器2次,修改名称为bg1,bg2即可,背景2接着背景1点上方设置位置. 2.摆放玩家主角在屏幕合适位置 3.添加金币按钮在屏幕上方 4.右键Canvas画布=>创建节点=>创建渲染节点=&

【UOJ Round #3】

枚举/二分 C题太神窝看不懂…… 核聚变反应强度 QwQ很容易发现次小的公约数一定是gcd的一个约数,然后……我就傻逼地去每次算出a[1],a[i]的gcd,然后枚举约数……这复杂度……哦呵呵... 正解是先找到a[1]的所有质因数啊……然后在刚刚那个算法的“枚举gcd的约数”的时候直接枚举这些质因数就好了…… 1 //UOJ Round3 A 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #in

BestCoder Round #11 (Div. 2) 前三题题解

题目链接: huangjing hdu5054 Alice and Bob 思路: 就是(x,y)在两个參考系中的表示演全然一样.那么仅仅可能在这个矩形的中点.. 题目: Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 216    Accepted Submission(s): 166 Problem De