大家好,欢迎来到codeforces专题。

今天选择的问题是Contest 1451场的D题,这是一道有趣简单的伪博弈论问题,全场通过的人有3203人。难度不太高,依旧以思维为主,坑不多,非常友好。

题目链接:https://codeforces.com/contest/1451/problem/D

废话不多说,我们直接来看问题。

题意

从前有两个人,一个叫Utkarsh,另外一个叫Ashish。这两个名字看起来有点怪,我猜可能出题人是老毛子的原因,老毛子的问题当中这两个名字经常出现。也许类似于我们的小红、小明这样的名字吧。

这两个人在一个2D的棋盘上玩移动棋子的游戏,一开始从原点出发,Ashish先手。每次可以把棋子向上或者是向右移动k个单位的距离。两人交替移动,游戏规定棋子距离原点的距离必须要小于d。当有人移动不了棋子的时候落败。

现在给出d和k,要求在两人都智商爆表的情况下,谁会获胜。

样例

首先输入一个整数t,表示测试数据的组数。接着输入t行,每行代表一个样例。每一行输入两个整数,分别代表d()和k()。

要求输出胜者的名字。

关于第一个样例的解释:

我们可以发现当两人轮流执行一个回合之后,Ashish一定无路可去,所以胜者是Utkarsh。

题解

一拿到手,我们会很自然地觉得这是一道博弈论的问题。

实际上看起来也非常像,两个人轮流游戏,包括游戏的一些细节,轮流移动,不能移动者落败,都很符合博弈论问题的特征。从博弈论入手的话,我们会想到必败态和必胜态之间的转化。

我们进一步分析的话,也不难想到思路。我们把这个平面想象成一个用一个扇形笼罩的区域,对于靠近扇形边境上的点,只有我们知道了坐标,就可以计算出来从原点出发到达这里需要的步数,步数知道了自然也就知道了最终是哪一个人落在了这个点。

这样我们首先确定下来边境的胜负状况之后,我们就可以逐渐往内层倒推,最终求解出原点的状态。这个推导的转移非常容易想明白,对于每个点来说它最多只有向右和向上两条路,对于该点做决策的人来说,只要这两个决策当中有一个能够到达自己的必胜态,那么该点自然也是必胜态。这其实有点动态规划的思想了,通过这种方法,我们可以求解出平面上每一个能够达到的点的状态。

看似这个问题就已经做完了,非常简单,但是我们稍微分析一下就会发现这样是不行的。道理也很简单,因为复杂度太大,会超时。

极端情况下当d的量级是1e5,并且k=1的时候,我们需要考虑的点的数量应该在1e10这个量级,这显然是不能接受的。那除了这个办法之外还有其他方法可行吗?

很多时候看似问题很难解决,往往是我们走错了路。我们一直想着怎么递推,怎么获取每个点的状态,其实一开始这个思路就错了。这个时候需要我们把这些念头放一放,回归到问题本身。

我们把自己代入先手的玩家,我们会想出什么策略?你会发现好像一时半会也没什么特别好的策略?但如果我们是后手玩家呢?你会发现好的策略可能没有,但是赖皮的套路却是存在的。因为这个扇形是一个四分之一圆,它是对称的。所以我们可以利用后发的优势镜像先手的行动,先手往上我们往右,先手往右我们往上,这样我们可以保证我们的点始终落在斜对角线。这样只要先手可以前进,那么后手就一定可以移动。也就是顺着下图的路线移动。

那这样岂不是先手必输吗?其实也不是的,也有例外。就是当后手无法回到斜线的时候,也就是说((x+1)k, xk)距离原点小于d,而((x+1)k, (x+1)k)大于d的时候。

这样我们就可以很方便写出代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include "time.h"
#include <functional>
#define rep(i,a,b) for (int i=a;i<b;i++)
#define Rep(i,a,b) for (int i=a;i>b;i--)
#define foreach(e,x) for (__typeof(x.begin()) e=x.begin();e!=x.end();e++)
#define mid ((l+r)>>1)
#define lson (k<<1)
#define rson (k<<1|1)
#define MEM(a,x) memset(a,x,sizeof a)
#define L ch[r][0]
#define R ch[r][1]
const int N=1000050;
const long long Mod=1000000007;
 
using namespace std;

int main() {
    int t;
    scanf("%d", &t);
    rep(z, 0, t) {
        long long d, k;
        scanf("%lld%lld", &d, &k);
        int n = d / (sqrt(2) * k);
        long long x = (n+1) * k;
        long long y = n * k;
        // 判断是否会出现((x+1)k, xk)可行的情况
        if (x * x + y * y > d * d) {
            puts("Utkarsh");
        }else {
            puts("Ashish");
        }
    }
    return 0;
}

这里有一个小小的坑,就是由于d的范围是1e5,那么当我们计算距离的时候由于用到平方会超过int的范围,所以需要改成long long。

这道题到这里就结束了,我们也可以看得出来,题目本身是不难的,但是解法没有那么容易想到。我个人觉得挺有意思的,希望大家也会喜欢。

今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、关注、转发)

codeforces 1451D,一道有趣的博弈论问题的更多相关文章

  1. 一道有趣的for循环题

    一道有趣的for循环题 今天在复习js基础知识时发现了一个for循环的题,第一眼看到直接懵逼了,没想到for循环竟然还可以这样玩?涨姿势了. 题目是这样的 for(i=0, j=0; i<10, ...

  2. Codeforces 1076G - Array Game(博弈论+线段树)

    Codeforces 题面传送门 & 洛谷题面传送门 一道 hot tea--听讲解时半懂不懂因为不知道题目意思,最后终究还是琢磨出来了( 首先注意到对于每个 \(a_i\),它具体是什么并不 ...

  3. Codeforces 1458E - Nim Shortcuts(博弈论+BIT)

    Codeforces 题目传送门 & 洛谷题目传送门 首先看到这样的题我们不妨从最特殊的情况入手,再逐渐推广到一般的情况.考虑如果没有特殊点的情况,我们将每个可能的局面看作一个点 \((a,b ...

  4. CodeForces 176C Playing with Superglue 博弈论

    Playing with Superglue 题目连接: http://codeforces.com/problemset/problem/176/C Description Two players ...

  5. 记一道有趣的Twitter面试题

    微信上的“程序员的那些事”想必是很多码农们关注的公众账号之一,我也是其粉丝,每天都会看看里面有没有什么趣事,前段时间“程序员的那些事”分享了一篇博文<我的Twitter技术面试失败了>挺有 ...

  6. 自家人不认识自家人——考你一道有趣的Javascript小题目

    今天的内容很简单,给大家分享一个有趣的Javascript小题目. 题目很简单,就是填空: var a = ______; var b = a; alert(a==b); // alert " ...

  7. 一道有趣的golang排错题

    很久没写博客了,不得不说go语言爱好者周刊是个宝贝,本来想随便看看打发时间的,没想到一下子给了我久违的灵感. go语言爱好者周刊78期出了一道非常有意思的题目. 我们来看看题目.先给出如下的代码: p ...

  8. Ural 1209. 1, 10, 100, 1000... 一道有趣的题

    1209. 1, 10, 100, 1000... Time limit: 1.0 secondMemory limit: 64 MB Let's consider an infinite seque ...

  9. 一道有趣的javascript编程题

    题目:实现以下功能 1. 点击按钮“打开新窗口”,打开新的子页面,要求新窗口的大小为400px X 200px 2. 输入地址信息,点击“确定”按钮,关闭该页面 3. 将子页面中输入的地址信息,回传到 ...

随机推荐

  1. 第15.31节 PyQt(Python+Qt)入门学习:containers容器类部件GroupBox分组框简介

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 容器部件就是可以在部件内放置其他部件的部件,在Qt Designer中可以使用的容器部件有 ...

  2. PyQt(Python+Qt)学习随笔:containers容器部件GroupBox分组框介绍

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.主要属性 GroupBox分组框是一个对多个部件进行编组的框架容器,可以带有标题(title属性 ...

  3. 第11.1节 Python正则表达式概述

    正则表达式是可匹配文本片段的模式,一个正则表达式指定了一个与之匹配的字符串集合.最简单的正则表达式为普通字符串,与它自己匹配.如正则表达式'python'与字符串'python'匹配.通过匹配,可以在 ...

  4. PyQt(Python+Qt)学习随笔:视图中的dragDropMode属性对dragEnabled和acceptDrops属性的影响

    老猿Python博文目录 老猿Python博客地址 在<PyQt(Python+Qt)学习随笔:QAbstractItemView的dragEnabled和dragDropMode属性的关系&g ...

  5. PyQt(Python+Qt)学习随笔:Qt Designer中spacer部件的orientation属性

    在Designer的spacers部件中有2个部件,分别是Horizontal Spacer和Vertical Spacer,这两个部件都有orientation属性,表示Spacer部件的方向. 如 ...

  6. 科大讯飞语音合成系统 V5.0绿色便携版

    中文名: 中科大讯飞Interphonic 5.0语音合成系统英文名: Interphonic 5.0版本: 5.0发行时间: 2006年制作发行: 中科大讯飞语言: 简体中文系统简介InterPho ...

  7. 影评网站Alpha版本-测试与发布

    影评网站Alpha版本-测试与发布 项目发布地址: http://120.78.161.21:8080/zhiying/ (建议使用Chrome或火狐浏览器打开,其他浏览器可能加载失败 一.Alpha ...

  8. HTML5中的自定义属性data-*

    在html5中,给元素添加自定义属性需要用到data-*,比如data-name,添加完data-自定义属性之后通过元素的dataset属性来访问其值. dataset与getAttribute/se ...

  9. NOIP2020 浙江 游记

    day - ? 由于 CSP-S 的失利,感觉这一次 NOIP 的心态反而是非常的淡定,感觉反正已经炸过一次了,再炸一次好像也没什么,就抱着这样的心态去考试的. day 1 考试当天起晚了,到考场的时 ...

  10. 题解-CmdOI2019 口头禅

    题面 CmdOI2019 口头禅 给 \(n\) 个 \(01\) 串 \(s_i\),\(m\) 个询问问 \(s_{l\sim r}\) 的最长公共子串长度. 数据范围:\(1\le n\le 2 ...