题目大意:
在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。一天琪露诺决定到河岸去追青蛙。小河是一列依次编号为0到N的格子,琪露诺只能从编号小的格子移动到编号大的格子。当她在格子i时,她只能走格子[i+L..i+R]中的格子。每一个格子都有一个冰冻指数A[i],编号为0的格子冰冻指数为0。走到一格就可以得到一格的冰冻指数A[i]。琪露诺希望能够在到达对岸时,获取最大的冰冻指数,琪露诺在编号0的格子上,只要她下一步的位置编号大于N就算到达对岸。
求最大获得的冰冻指数。
对于60%的数据:N <= 10,000
对于100%的数据:N <= 200,000
对于所有数据 -1,000 <= A[i] <= 1,000且1 <= L <= R <= N
题解:
这题其实跟2017noip普及T4差不多一样的思路,只是少了二分,而且他可以越界即可以跑到[n+1..n+r]这些的位置。
设fi表示走到第i个的最大冰冻值,易得状态转移:
fi=max{fj}+ai 保证i-r≤j≤i-l
这样的实现是 O(N^2)的
很明显会TLE,得分为60,
而我们可以想到维护一个单调队列,使得我们每次可以O(1)查询到最大的fj,优化成O(N)
而单调队列,
所以我们可以用一个k去依次加入fk进入单调队列,
一个i去枚举位置,那么每次我们先将满足的fk加入,
即当max{1,d-ans’}<=xi-xk<=d+ans’则加入,
也不要忘了将现在位置已经够不到i的亦或者无法走到第k步的给踢掉!
最后答案在f[n+1..n+r]之间找,我一开始是f[n+1]结果就狂WA,好毒。
代码:
var
f,cmax,a:array [0..400001] of longint;
head,tail,l,r,ans,i,k,n:longint;
function max(aa,bb:longint):longint;
begin
if aa>bb then exit(aa);
exit(bb);
end;
begin
readln(n,l,r);
for i:=0 to n do read(a[i]);
k:=0;
head:=1;
tail:=0;
f[0]:=a[0];
for i:=1 to n+r do
begin
f[i]:=-1;
while (head<=tail) and (cmax[head]<i-r) do inc(head);
while (k<i) and ((k<i-r) or (f[k]=-1)) do inc(k);
while (k<i) and (k<=i-l) do
begin
while (head<=tail) and (f[k]>=f[cmax[tail]]) do dec(tail);
inc(tail);
cmax[tail]:=k;
inc(k);
end;
if head<=tail then
f[i]:=f[cmax[head]]+a[i];
end;
ans:=-maxlongint;
for i:=n+1 to n+r do
ans:=max(ans,f[i]);
writeln(ans);
end.