NOIP 2017 普及组 跳房子 jump

NOIP 2017 普及组 跳房子 jump_第1张图片
NOIP 2017 普及组 跳房子 jump_第2张图片
NOIP 2017 普及组 跳房子 jump_第3张图片
NOIP 2017 普及组 跳房子 jump_第4张图片

题解:

这题因为答案是有已知范围[0..xn],所以我们能够去二分答案ans,这个都能想到吧…
时间复杂度:O(log2 xn)
然后我们发现对于每个答案ans’能否满足,我们就可以打个简单的dp,
f[i]表示起点0到第i个位置能得到的最大分数.
f[i]=max{f[j]}+si
j满足max{1,d-ans’}<=xi-xj<=d+ans’
时间复杂度:O(N^2)
当发现有fi≥m则返回true
然后向前二分
反之则向后二分
时间复杂度:O(log2 xn*n^2)
很明显只有50分,

而我们可以发现对于fi我们要找的只是fj的最大值,

因为xi递增,那么我们就可以用单调队列去使这个最大值可以直接得出!

但是单调队列的维护就要注意了,
如果直接去弄的话,那么 xi-xj < max{1,d-ans’} 的情况就会出现,这时候你的单调队列的维护就会出现问题…

所以我们可以用一个j去依次加入fj进入单调队列,
一个i去枚举位置,那么每次我们先将满足的fj加入,
即当max{1,d-ans’}<=xi-xj<=d+ans’则加入,也不要忘了将现在位置已经够不到xi的踢掉!
这样dp就优化到O(N)

时间复杂度就变成了O(log2 xn*n)

var
   a:array [0..500001,1..2] of longint;
   cmax:array [0..500001] of longint;
   f:array [0..500001] of int64;
   l,r,ans,mid,i,n,m,d:longint;
   rp:boolean;

function max(aa,bb:int64):int64;
begin
   if aa>bb then exit(aa);
   exit(bb);
end;

function need(qd,pd:longint):boolean;
var
   i,head,tail,j,k:longint;
begin
   head:=1; tail:=1;
   f[0]:=0; cmax[1]:=0;
   for k:=1 to n+1 do
      if (a[k,1]<=pd) and (a[k,1]>=qd) then break;
   j:=k;
   for i:=k to n do
     begin
        f[i]:=-1;
          while (head<=tail) and (a[cmax[head],1]1]-pd) do inc(head);

          while (jand ((a[i,1]-pd>a[j,1]) or (f[j]=-1)) do inc(j);

          while (jand (a[i,1]-qd>=a[j,1]) do
          begin
               while (head<=tail) and (f[j]>=f[cmax[tail]]) do dec(tail);
               inc(tail);
               cmax[tail]:=j;
               inc(j);
          end;

          if head<=tail then
          begin
               f[i]:=a[i,2]+f[cmax[head]];
               if f[i]>=m then exit(true);
          end;
     end;
  exit(false);
end;

begin
     readln(n,d,m);
     a[0,1]:=0; a[0,2]:=0;
     for i:=1 to n do
       readln(a[i,1],a[i,2]);
     l:=0; r:=a[n,1];
     ans:=-1;
     while l<=r do
     begin
          mid:=(l+r) div 2;
          rp:=need(max(1,d-mid),d+mid);
              if rp then begin ans:=mid; r:=mid-1 end
                    else l:=mid+1;
     end;
     writeln(ans);
end.


你可能感兴趣的:(pascal,二分&三分,单调队列&单调栈,动态规划)