赛后题解: 2022江苏省赛 C. Jump and Treasure

文章介绍了一道关于游戏的编程题,玩家从左边的柱子开始,按照一定的跳跃能力向右移动,目标是获取最多的金币。每个柱子上可能有正或负的金币奖励。题目要求使用动态规划和单调队列优化来解决在不同级别下玩家能获得的最大金币数。文章强调了单调队列在区间最大值查询中的应用,并指出初始化和避免额外步骤的重要性。给出了C++代码示例来实现解决方案。
摘要由CSDN通过智能技术生成

传送门:CF

题目描述:

Tom likes playing a video game recently. The rules of this game are as follows. The game is played 
on an x-axis. There are a total of n+1 pillars in the game, which are arranged in a row from left to 
right. The pillars are numbered from 0 to n. The coordinate of the pillar numbered i is x=i. There is 
also an infinite platform in the game in the range of [n+1,+∞). Players can win by jumping to any 
position within this range.
Players start from the pillar numbered 0 and can only jump from left to right, i.e. the coordinates must 
increase. And he can only jump on the pillars or the platform, otherwise, he will fall into the void and 
fail the game. In addition, his jumping ability is limited, and the distance of each jump does not 
exceed p.
Except for the pillar numbered 0, there will be a treasure chest on each remaining pillar. The treasure 
chest on the pillar numbered i will have ai gold coins. However, there are some trap chests (ai<0) 
where he will lose |ai| gold coins.
This game has n levels. Tom can only jump to the pillars numbered with multiples of i in the i-th level. 
Now there are q queries, each of which contains a number x, asking the maximum number of gold 
coins Tom can get when he wins at level x. It's possible that Tom opens too many trap chests on the 
way and gets negative gold coins.
输入:
5 3 4
2 5 -6 -4 3
1
2
3
输出:
10
5
-6

一道比较坑的单调队列优化dp题

vp的时候dp方程很好看出来,就是一个简单的线性dp,当前点显然可以由之前可以跳到该点的点转移过来,也就是:

d p [ i ] = m a x ( d p [ i − k ∗ q ] ) + a [ i ] dp[i]=max(dp[i-k*q])+a[i] dp[i]=max(dp[ikq])+a[i]    其中 k ∗ q < p k*q<p kq<p

但是写出来之后就会发现对于每一个点我们想要求出max的那一个点的话需要枚举,这样的复杂度将会达到 n 2 n^2 n2,这道题肯定过不去.那么对于区间求最大值,我们可以单调队列来进行优化.如果对单调队列不是很熟悉,可以看看这篇博客

对于单调队列来说,我们只需要维护每一个点 [ i − l , i − r ] [i-l,i-r] [il,ir]这一段区间即可, l , r l,r l,r是一步最短和最长能走的距离.并且我们发现我们只能走q的倍数的点,所以对于不是q的倍数的点,我们应该直接跳过(这样就可以跳过我们的初始化了,因为剩下的点全都是可以走到的.不然的话,我们需要初始化 − i n f -inf inf,这样复杂度又变成了 N 2 N^2 N2),感觉这道题的这个选点操作还是有独到之处的,巧妙的避免了初始化的问题

坑点:1.首先注意我们q的倍数的跳跃只是在柱子之间是这样的,但是在最后一步也就是从柱子跳出平台可以不用遵守这个,也就是说最后一步可以跳p的长度
2.这道题需要开longlong,并且初始化 − i n f -inf inf的时候不要忘记我们的ans应该赋值为-0x3f3f3f3f3f3f3f3f,而不是-0x3f3f3f3f,赛场上我就是因为改了longlong忘记改这个卡到了比赛结束

下面是具体的代码部分:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define int long long
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n,q,p;int a[1000010],dp[1000010];
int dq[1000010];
int DP(int num) {
	dp[0]=0;
	int ans=-ll_maxn;
	int head=1,tail=0;
	int l=num,r=p/num*num;
	for(int i=num;i<=n;i+=num) {
		while(head<=tail&&dq[head]<i-r) head++;
		while(head<=tail&&dp[dq[tail]]<=dp[i-l]) tail--;
		dq[++tail]=i-l;
		dp[i]=dp[dq[head]]+a[i];
		if(i+p>n) ans=max(ans,dp[i]);
	}
	return ans;
}
signed main() {
	n=read();q=read();p=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=q;i++) {
		int num=read();
		if(num>p) printf("Noob\n");
		else printf("%lld\n",DP(num));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值