SSL P2152 琪露诺___dp+单调队列

题目大意:

在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。一天琪露诺决定到河岸去追青蛙。小河是一列依次编号为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.
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值