传送门: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[i−k∗q])+a[i] 其中 k ∗ q < p k*q<p k∗q<p
但是写出来之后就会发现对于每一个点我们想要求出max的那一个点的话需要枚举,这样的复杂度将会达到 n 2 n^2 n2,这道题肯定过不去.那么对于区间求最大值,我们可以单调队列来进行优化.如果对单调队列不是很熟悉,可以看看这篇博客
对于单调队列来说,我们只需要维护每一个点 [ i − l , i − r ] [i-l,i-r] [i−l,i−r]这一段区间即可, 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;
}