题目描述
在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。
某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来。但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸。于是琪露诺决定到河岸去追青蛙。
小河可以看作一列格子依次编号为 0 到 N,琪露诺只能从编号小的格子移动到编号大的格子。而且琪露诺按照一种特殊的方式进行移动,当她在格子 i 时,她只移动到区间 [i+L,i+R] 中的任意一格。你问为什么她这么移动,这还不简单,因为她是笨蛋啊。
每一个格子都有一个冰冻指数 Ai,编号为 0 的格子冰冻指数为 0。当琪露诺停留在那一格时就可以得到那一格的冰冻指数 Ai。琪露诺希望能够在到达对岸时,获取最大的冰冻指数,这样她才能狠狠地教训那只青蛙。
但是由于她实在是太笨了,所以她决定拜托你帮它决定怎样前进。
开始时,琪露诺在编号 0 的格子上,只要她下一步的位置编号大于 N 就算到达对岸。
输入格式
第一行三个正整数 N,L,R。
第二行共 N+1 个整数,第 i 个数表示编号为 i−1 的格子的冰冻指数 Ai−1。
输出格式
一个整数,表示最大冰冻指数。
样例
样例输入
5 2 3
0 12 3 11 7 -2
样例输出
11
提示
对于 60% 的数据,N≤104。
对于 100% 的数据,N≤2×105,−103≤Ai≤103,1≤L≤R≤N。数据保证最终答案不超过 231−1。
算法1
(暴力DP) O(n2)
TLE
设fi为跳跃到i的最大指数,则fi=max(fj)+ai(i−r≤j≤i−l<i)
注意:有的位置是无法转移的。
解决方法:
1.对于能够转移到的点打上标记。
2.初始化时,将所有点的fi设为−inf,对于无法转移的点,转移后fi仍为−inf,不影响结果判断。
时间复杂度
参考文献
Python 代码
n,l,r=map(int,input().split())
N=n+l+10
a=list(map(int,input().split()))+[0]*l
f=[-float('inf')]*N;f[0]=0
for i in range(1,n+l+1):
for j in range(i-r,i-l+1):
if j>=0:
f[i]=max(f[i],f[j]+a[i])
res=-float('inf')
for i in range(n+1,n+l+1):
res=max(res,f[i])
print(res)
算法2
(DP,单调队列) O(n)
AC
对于状态转移方程:fi=max(fj)+ai(i−r≤j≤i−l<i)
每次要找i−r→i−l范围的最大值,即动态求解固定长度的区间最值,可用单调队列。
设i为区间的右端点,i−l+r为区间左端点,单调队列求解区间最值,更新fi+l。
时间复杂度
参考文献
Python 代码
n,l,r=map(int,input().split())
N=n+l+10
a=list(map(int,input().split()))+[0]*l
f=[-float('inf')]*N;f[0]=0
q=[0]*N;hh=0;tt=-1
for i in range(n+1):
while hh<=tt and f[q[tt]]<f[i]:
tt-=1
tt+=1;q[tt]=i
while hh<=tt and q[hh]-l+r<i:
hh+=1
f[i+l]=f[q[hh]]+a[i+l]
res=-float('inf')
for i in range(n+1,n+l+1):
res=max(res,f[i])
print(res)