Codeforces_943_D_Permutation Game

news/2024/10/22 1:50:47

题目指路: https://codeforces.com/contest/1968/problem/D

题目大意

Bodya, Sasha 两人博弈

输入为

  1. 一个n的排列p
  2. 一个长为n的数组a(a[i]代表在i位置的分数)
  3. 可操作次数k
  4. 和各自的起点

每次操作,若玩家的位置为pos

  1. 玩家先加上当前位置下标对应的分数a[pos]
  2. 然后可以选择:
    • 留在当前位置pos
    • 或者前往该位置在排列的对应元素p[pos]

若双方都以最优策略游戏,求最后获胜的人,输出姓名,若平局则输出Draw

思路

由排列的性质可以知道,如果以i->p[i]的规则建图e的话,会形成一个或多个有向环
所以题目等价于:求B和S在各自出发点所在的环上操作k次的最大得分
每次操作:要么留在原地,要么沿着有向边往下走一步
比较妙的地方,同时也是我tle的地方在于:对这个最大值的求法

如果k足够大,那么得分最大化的策略很显然:
走到环上得分最大的点上,然后一直不动。

但是k有限制,那么在点pos:

  1. 如果a[e[pos]]>a[pos],也就是下一个点的得分大于当前点,那么必然移动。
  2. 反之,那么可能移动/不移动。状态无法确定。

求得分最大值

首先得注意到:最大操作次数是: min(n,k)
k是题目给的步数限制,这个容易理解
但是也要注意到,一个环的阶(就是组成环的点的数量)最大为n,此时所有的排列只组成一个环。
有了前面对k有限制下的分析,可以知道:
一个点如果在环上一直往下走,在回到本身之前,必然在某点停下。
注意到这点很重要,因为知道了这点我们可以枚举停下的位置,然后在所有这些位置里求得分最大值,这个最大值就是该玩家的得分最大值。
在点u停下的得分=得分前缀和+(k-已操作次数)*a[u]
每个点的得分可以由前面的点递推得到

更细节的讲解可以见代码 > <

AC代码

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;ll e[200005],a[200005]; //e存图,a保存得分
ll n,k,pb,ps,p[200005]; //p保存n的排序,pb和ps是B和S两位玩家的出发点ll score(ll pp,ll lmt);
void solve();ll score(ll pp,ll lmt){vector<bool> vis(n+1,false); //vis数组记录点是否走过(由分析可知环上每个点最多走一次)ll ans=0;	//ans维护得分最大值ll sum=0;  //sum记录得分前缀和ll cnt=0;  //cnt记录已操作次数while(!vis[pp] && cnt<=lmt){ //两层限制:(1) 回到自身停下 (2)不能超过最大操作次数lmtans=max(ans,sum+a[pp]*(k-cnt));	//得分=前缀和+剩余操作次数*该点得分sum+=a[pp];	//前缀和更新vis[pp]=true; //该点标记为走过pp=e[pp]; //往下走cnt++; //操作次数自增}return ans; //返回最大值
}void solve(){cin>>n>>k>>pb>>ps;for(ll i=1;i<=n;i++){ //存序列,建图cin>>p[i];e[i]=p[i];}for(ll i=1;i<=n;i++){ //存得分cin>>a[i];}ll lmt=min(n,k);  //操作的最大次数限制ll bb=score(pb,lmt);ll ss=score(ps,lmt);// cerr<<bb<<' '<<ss<<'\n';if(bb==ss){cout<<"Draw\n";} else if(bb>ss){cout<<"Bodya\n";} else {cout<<"Sasha\n";}
}
int main(){ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);ll t=1;cin>>t;while(t--){solve();}return 0;
}

收获

对我来说,这题的突破点在于意识到“回到自身前必然在某点停下”这条信息,并且利用这点枚举终点求最大值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/74439.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

[Linux Mint]安装搜狗输入法

造冰箱的大熊猫@cnblogs 2024/10/22, Linux Mint 1、从官网下载搜狗拼音输入法的deb包2、安装deb包sudo apt deb sogoupinyin.deb 3、设置输入法框架 - 启动Input Method,将“Input method framework”设置为fcitx - 选择“Simplified Chinese”,点击“Install the language…

chapter4

通过python process.run.py -h命令了解了process.run.py的可用的选项 题外话(关于/home目录的): /home 目录是 Linux 系统中用于存储用户个人文件的地方。每个用户在 /home 下都有一个以其用户名命名的子目录,用于存放该用户的个人数据和设置。以下是一些 /home 目录的特点…

如何以最简单的方式传输文件到开发板上-lrzsz-ZModem

在某鱼上闲逛的时候,看到树莓派A+这个型号的板子,很便宜30来块钱,有6ULL的性能。 但是既没有网口、也没有WiFi,只有一个usb,电脑和它传数据岂不是非常麻烦?其实有一个非常好用的协议叫ZModem,它的设计就是主要为了能在串口这种几乎无需配置的连接协议上传输文件。类似的…

东山Pi柒号-3-STM32MP1 引导链概述

进行移植前先看看ST官网的一些资料,了解芯片的工作方式: STM32MP1 引导链概述 https://wiki.stmicroelectronics.cn/stm32mpu/wiki/STM32MP1_boot_chain_overview启动步骤如下BROM(BL1):芯片内部程序,根据BOOT PIN读取对应启动设备里的程序到内部SYSRAM执行,工作在在Secur…

派生类

派生类 1. 派生类2. 派生类对象定义时调用构造函数的顺序 Man man;3. public、protected、private 4. 函数遮蔽

2024年好用的短链接短网址工具推荐

小码短链接,作为一款专业的短链接生成和统计工具,能够帮助您轻松应对各种场景需求,让运营工作变得简单高效。 小码短链接功能介绍 1. 链接缩短 小码短链接不仅可以缩短您的原始链接,还可以提供简洁美观的短链接形式。通过短链接,您可以有效地减少短信或营销内容的字数,从…

Python找不到项目模块解决方法

BiliBili VsCode在使用Python过程中遇到找不到项目模块的问题问题描述 目录及代码如下的项目结构demo ├─ main.py └─ src├─ __init__.py├─ a.py└─ b.py在"src/a.py"文件中有一个方法,代码如下def xxc():print("hello")在"src/b.py"和…

循环结构程序设计

为什么需要循环控制 循环结构或称重复结构 几乎每一种计算机高级语言都提供了循环控制,用来处理需要进行的重复操作 大多数的应用程序都会包含循环结构 循环结构和顺序结构、选择结构是结构化程序设计的3中基本结构,它们是各种复杂程序的基本构成单元。 用 while 语句实现循环…