首页 > 其他分享 >道路游戏——题解

道路游戏——题解

时间:2022-11-30 23:00:13浏览次数:46  
标签:le 游戏 get 题解 机器人 工厂 金币 道路 dp

单调队列优化-道路游戏

[NOIP2009 普及组] 道路游戏

题目描述

小新正在玩一个简单的电脑游戏。

游戏中有一条环形马路,马路上有 \(n\) 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接。小新以某个机器人工厂为起点,按顺时针顺序依次将这 \(n\) 个机器人工厂编号为 \(1\sim n\),因为马路是环形的,所以第 \(n\) 个机器人工厂和第 \(1\) 个机器人工厂是由一段马路连接在一起的。小新将连接机器人工厂的这 \(n\) 段马路也编号为 \(1\sim n\),并规定第 \(i\) 段马路连接第 \(i\) 个机器人工厂和第 \(i+1\) 个机器人工厂(\(1\le i\le n-1\)),第 \(n\) 段马路连接第 \(n\) 个机器人工厂和第 \(1\) 个机器人工厂。

游戏过程中,每个单位时间内,每段马路上都会出现一些金币,金币的数量会随着时间发生变化,即不同单位时间内同一段马路上出现的金币数量可能是不同的。小新需要机器人的帮助才能收集到马路上的金币。所需的机器人必须在机器人工厂用一些金币来购买,机器人一旦被购买,便会沿着环形马路按顺时针方向一直行走,在每个单位时间内行走一次,即从当前所在的机器人工厂到达相邻的下一个机器人工厂,并将经过的马路上的所有金币收集给小新,例如,小新在 \(i\)(\(1\le i\le n\))号机器人工厂购买了一个机器人,这个机器人会从 \(i\) 号机器人工厂开始,顺时针在马路上行走,第一次行走会经过 \(i\) 号马路,到达 \(i+1\) 号机器人工厂(如果 \(i=n\),机器人会到达第 \(1\) 个机器人工厂),并将 \(i\) 号马路上的所有金币收集给小新。游戏中,环形马路上不能同时存在 \(2\) 个或者 \(2\) 个以上的机器人,并且每个机器人最多能够在环形马路上行走 \(p\) 次。小新购买机器人的同时,需要给这个机器人设定行走次数,行走次数可以为 \(1~p\) 之间的任意整数。当马路上的机器人行走完规定的次数之后会自动消失,小新必须立刻在任意一个机器人工厂中购买一个新的机器人,并给新的机器人设定新的行走次数。

以下是游戏的一些补充说明:

  1. 游戏从小新第一次购买机器人开始计时。

  2. 购买机器人和设定机器人的行走次数是瞬间完成的,不需要花费时间。

  3. 购买机器人和机器人行走是两个独立的过程,机器人行走时不能购买机器人,购买完机器人并且设定机器人行走次数之后机器人才能行走。

  4. 在同一个机器人工厂购买机器人的花费是相同的,但是在不同机器人工厂购买机器人的花费不一定相同。

  5. 购买机器人花费的金币,在游戏结束时再从小新收集的金币中扣除,所以在游戏过程中小新不用担心因金币不足,无法购买机器人而导致游戏无法进行。也因为如此,游戏结束后,收集的金币数量可能为负。

现在已知每段马路上每个单位时间内出现的金币数量和在每个机器人工厂购买机器人需要的花费,请你告诉小新,经过 \(m\) 个单位时间后,扣除购买机器人的花费,小新最多能收集到多少金币。

输入格式

第一行 \(3\) 个正整数 \(n,m,p\),意义如题目所述。

接下来的 \(n\) 行,每行有 \(m\) 个正整数,每两个整数之间用一个空格隔开,其中第 \(i\) 行描。

述了 \(i\) 号马路上每个单位时间内出现的金币数量($1\le $ 金币数量 \(\le 100\)),即第 \(i\) 行的第 \(j\)(\(1\le j\le m\))个数表示第 \(j\) 个单位时间内 \(i\) 号马路上出现的金币数量。

最后一行,有 \(n\) 个整数,每两个整数之间用一个空格隔开,其中第 \(i\) 个数表示在 \(i\) 号机器人工厂购买机器人需要花费的金币数量($1\le $ 金币数量 \(\le 100\))。

输出格式

共一行,包含 \(1\) 个整数,表示在 \(m\) 个单位时间内,扣除购买机器人花费的金币之后,小新最多能收集到多少金币。

样例 #1

样例输入 #1

2 3 2 
1 2 3 
2 3 4 
1 2

样例输出 #1

5

提示

对于 \(40\%\) 的数据,\(2\le n\le 40\),\(1\le m\le 40\)。

对于 \(90\%\) 的数据,\(2\le n\le 200\),\(1\le m\le 200\)。

对于 \(100\%\) 的数据,\(2\le n\le 1000\),\(1\le m\le 1000\),\(1\le p\le m\)。

NOIP 2009 普及组 第四题

题解

首先本题是最优性问题,容易想到动态规划,那么我们来分析此题的动态规划做法

状态刻画

最朴素的想法:设\(dp[i,j,k]\)表示在时刻\(i\),上一个机器人在\(j\),走\(k\)步的最大收益

我们发现,在转移的时候,最后一个维度可以枚举消掉,故略去\(k\),继续由于我们可以从任意一个地方买机器人,于是机器人在哪里买的也不重要,省去第二维

最终得到\(dp[i]\)表示在时刻\(i\)所能得到的最大收益

状态转移

考虑转移。明显\(dp[i]\)的转移需要我们枚举上一个机器人在哪里出发,走了多少步,分别记为\(j,k\)

那么有:

\[dp[i]=\max_{0\le j< n}\left\lbrace\max_{1\le k\le q}\lbrace dp[i-k]+val[i-k,j,k]-cost[j-k]\rbrace \right\rbrace \]

其中\(cost\)表示买机器人所花的钱,而\(val\)表示一路上的收益

这里为了代码的方便,我们采取将点权下放到边权的形式,将边\((i,i+1)\)的权值记在\(i+1\)上
为了用模运算简单处理环,我们需要将编号从零开始,所以读入时不会有任何改变

下一步,我们考虑如何将\(val\)降维,记\(a[i,j]\)表示在时刻\(i\)第\(j\)条路的权值,记\(get(i)\)表示节点\(i\)在环上的位置(模运算)

将\(val[i,j,k]\)展开有:

\[val[i,j,k]=\sum_{p=1}^ka[i+p,get(j+p)] \]

将\(i\)用\(i-k\)代替有

\[val[i-k,j,k]=\sum_{p=1}^ka[i-k+p,get(j+p)] \]

考虑进行转化,如果我们设\(f[i,j]\)表示前\(i\)个时间,最终走到\(j\)上的金币总和,那么有\(f[i,j]=\sum_{k=0}^{i}a[i-k,get(j-k)]\)

那么\(val[i-k,j,k]\)就等价于\(f[i,j]-f[i-k,get(j-k)]\),成功降维

接着,状态转移方程就可以改写成:

\[dp[i]=\max_{0\le j< n}\left \lbrace\max_{1\le k\le q}\lbrace dp[i-k]+f[i,j]-f[i-k,get(j-k)]-cost[j-k]\rbrace \right\rbrace \]

观察到\(f[i,j]\)只会用到一个矩形的对角线部分,于是预处理也只是\(O(nm)\)

需要注意的是我们在处理\(f\)的时候别忘记\(n\)对应的是\(0\)
到此,我们得到了一个复杂度为\(O(nmq)\)的垃圾算法

转移优化

观察这个DP式子,如果我们把\(i,j\)看作定值,那么状态转移方程可以改写为

\[dp[i]=\max_{0\le j< n}\left\lbrace\max_{1\le k\le q}dp[i-k]-f[i-k,get(j-k)]-cost[j-k]+f[i,j]\right\rbrace \]

记\(rec[i,j]=dp[i]-f[i,j]-cost[j]\)

状态转移方程就是\(dp[i]=\max_{0\le j< n}\left\lbrace\max_{1\le k\le q}\lbrace rec[i-k,j-k]+f[i][j]\rbrace \right\rbrace\)

考虑如何优化掉这个式子,这个样子非常像单调队列优化,只是我们如何定下单调队列优化的策略

考虑两个决策\((k_1,k_2),(k'_1,k'_2)\),如果\(k_1<k_1'并且rec[k_1,k_2]<rec[k_1',k_2']\),那么决策\((k_1,k_2)\)就是无用决策,可以排除

因为我们的决策涉及到了两个变量,就需要多个单调队列,并且我们需要考虑的是,一个决策\((k_1,k_2)\)对怎样的询问\((i,j)\)能够产生贡献

注意观察原来的\(DP\)方程\(dp[i]=\max_{0\le j< n}\left\lbrace \max_{1\le k\le q}dp[i-k]-f[i-k,get(j-k)]-cost[j-k]+f[i,j]\right\rbrace\),会发现\(rec\)部分有一个项\(f[i-k,get(j-k)]\),这个项意味着什么呢,意味着\(i-k-get(j-k)=get(i-j)\)(这一步成立是因为\(get\)函数本身基于模运算,可以支持交换律等)的决策,由此,所有满足\(k_1-k_2=get(i-j)\)的决策都是询问\((i,j)\)的候选决策

这启发我们按照\(get(i,j)\)来划分决策,分成不同的单调队列进行维护,最终就可以将复杂度优化至\(O(nm)\)

#include<bits/stdc++.h>
using namespace std;
#define N 1005
int n,m,p,dp[N],a[N][N],f[N][N],cost[N],l[N],r[N];
int pos(int x){return (x%n+n)%n;}
int get(int x,int y){return ((y-x)%n+n)%n;}
struct node{
	int pos,num;
}rec[N][N];
signed main(){
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++){
      	  scanf("%d",&a[j][i]); 
      	  if(i==n)a[j][0]=a[j][i];
	  }
    for(int i=1;i<=m;i++)
     	for(int j=0;j<n;j++)
        	f[i][j]=f[i-1][pos(j-1)]+a[i][j];
	for(int i=0;i<n;i++){
        scanf("%d",&cost[i]);
        rec[i][++r[i]].num=-cost[i],l[i]++;
    }
	memset(dp,-0x3f,sizeof dp);
	dp[0]=0;
	for(int i=1;i<=m;i++){
		for(int j=0;j<n;j++){
			int id=get(i,j); 
			while(l[id]<=r[id] && rec[id][l[id]].pos+p<i) l[id]++;
		    if(l[id]<=r[id]) 
		      dp[i]=max(dp[i],rec[id][l[id]].num+f[i][j]);
		}
		for(int j=0;j<n;j++){
			int id=get(i,j);
			while(l[id]<=r[id] && rec[id][r[id]].num<=dp[i]-f[i][j]-cost[j])
			  r[id]--;
			rec[id][++r[id]]=(node){i,dp[i]-f[i][j]-cost[j]};
		}
	}
	printf("%d\n",dp[m]);
	return 0;
}

标签:le,游戏,get,题解,机器人,工厂,金币,道路,dp
From: https://www.cnblogs.com/oierpyt/p/16940104.html

相关文章

  • 题解——红黑树
    进制运算-红黑树题目描述红黑树是一类特殊的二叉搜索树,其中每个结点被染成红色或黑色。若将二叉搜索树结点中的空指针看作是指向一个空结点,则称这类空结点为二叉搜索树的......
  • 题解——GCD
    给定正整数\(n\),求\(1\lex,y\len\)且\(\gcd(x,y)\)为素数的数对\((x,y)\)有多少对。\(n\le10^7\)题解做法1题意即为求\(S=\sum_{质数p|n}\sum_{i=1}^n\sum_{......
  • 题解——阿狸与桃子的游戏
    边权均分-巧妙的阿狸和桃子的游戏[国家集训队]阿狸和桃子的游戏题目描述阿狸和桃子正在玩一个游戏,游戏是在一个带权图G=(V,E)上进行的,设节点权值为w(v),边权为c(e)。游......
  • 分组——题解
    分组题目背景大样例可在页面底部「附件」中下载。题目描述小C在了解了她所需要的信息之后,让兔子们调整到了恰当的位置。小C准备给兔子们分成若干个小组来喂恰当的......
  • KDOI-3还原数据题解
    「KDOI-03」还原数据题目描述小E正在做一道经典题:给定一个长度为\(n\)的序列\(a\)和\(q\)个操作,操作共有\(2\)种类型:\(\tt{1~l~r~x}\):对于所有\(l\lei\le......
  • 题解——星之界
    题解考虑化简这个可恶的式子\[\prod\limits_{i=l}^{r}C_{\sum_{j=l}^{i}a_j}^{a_i}\]拆开,设\(S\)为前缀和数组\[=\prod^r_{i=l}\frac{(S_i-S_{l-1})!}{a_i!(S_i-S......
  • P8858题解
    折线题目描述平面直角坐标系的第一象限内有一块左下角为\((0,0)\)右上角为\((10^{100},10^{100})\)的矩形区域,区域内有正偶数个整点,试求出这样一条从\((0,0)\)出发......
  • 题解 P1902 刺杀大使
    题解P1902刺杀大使首先注意到,只需要到达一个开关,就可以开启所有开关(打开所有门)所以我们就可以想到,我们要寻找一条从任意\(1-m\)开关(因为访问一个开关就可以开启所有......
  • 【Python】水仙花数、百钱买百鸡、CRAPS游戏、斐波那契数列、完美数、素数
    1.寻找水仙花数水仙花数:是一个3位数,每一位上数字的立方和正好等于它本身,如:13+53+33=153,则153就是一个水仙花数,也称为超完全数字不变数、自恋数、自幂数、阿姆斯特朗数......
  • 你必须要知道的JavaScript数据结构与面试题解答
    英文原文|https://dev.to/educative/7-javascript-data-structures-you-must-know-4k0m原文作者|RyanThelin和AmandaFawcett译文翻译|web前端开发(web_qdkf)解决编码......