大家好,欢迎来到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. url的组成结构信息

    http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name 从上面的URL可以看出,一个完整的 ...

  2. PyQt(Python+Qt)学习随笔:QAbstractItemView的autoScroll和autoScrollMargin属性

    老猿Python博文目录 老猿Python博客地址 QAbstractItemView的autoScroll属性用于确认鼠标在视口边缘时是否自动滚动内容,默认值为True,autoScrollMarg ...

  3. CTF流量分析题大全(掘安攻防平台)

    突然想做一下流量分析题,记得掘安攻防实验室上面有很多的流量分析题目,故做之 流量分析题一般使用的都是wireshark,(流量分析工具中的王牌 夺取阿富汗 说了分析http头,所以直接过滤http协议 ...

  4. Hello!OA!Hello!工作流!寻找OA和工作流的旅途记录

    最近新到了一家公司,这家公司做的人力资源管理,需要一个OA系统,所以就让我做一个选型,经过我2周时间的筛选,试用,沟通,测试,最终确定了几款,这个艰辛的路程,在这里记录一下~ 寻找OA的路程----- ...

  5. Echarts的食用方式

    写在前面: 最近项目中用到了Echarts做趋势图,博主通过万能的度娘研究了一下.Echarts字段的使用基本都写在代码注释里了,这是博主的第一篇博客,如果哪里写的不好望大家见谅,最后希望本篇博客对大 ...

  6. 剑指offer二刷——数组专题——数组中出现次数超过一半的数字

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  7. js 实现字符串翻转

    字符串作在程序中是非常常见的,因为程序中绝大部分的数据都可以当作字符串来处理.在这里介绍几种翻转字符串的方法. (1)使用字符串函数 //使用数组翻转函数 function reverseString ...

  8. v-lazyload数据变化图片不切换

    这个问题让我很困惑,明明得到的商品数据已经改变了,但是就图片不变化,随后找到了解决办法,那就是多加一个动态的key <img v-lazy="item.productImage&quo ...

  9. A Simple Framework for Contrastive Learning of Visual Representations 阅读笔记

      Motivation 作者们构建了一种用于视觉表示的对比学习简单框架 SimCLR,它不仅优于此前的所有工作,也优于最新的对比自监督学习算法, 而且结构更加简单:这个结构既不需要专门的架构,也不需 ...

  10. 程序员必读的 99 本书籍 & 资源

    作为程序员,始终要保持学习,一直带着纸质书还是很不便的,因此电子书对于我们还是挺需要的.为了方便广大的小伙伴也能方便找到对应的电子书,我花费洪荒之力从各个搜索网站收集了几百本常用的电子书,找到了,我要 ...