jzoj P1331 超级教主___dp+单调队列

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/79254333

题目大意:

LHX教主很能跳,跳需要消耗能量,每跳1米就会消耗1点能量。
教主为了收集能量,来到了一个神秘的地方,教主的正上方每100米处就有一个能量球(也就是这些能量球位于海拔100,200,300……米处),每个能量球所能提供的能量是不同的,一共有N个能量球(也就是最后一个能量球在N×100米处)。教主为了想收集能量,想跳着吃完所有的能量球。教主可以自由控制他每次跳的高度,接着他跳起把这个高度以下的能量球都吃了,他便能获得能量球内的能量,接着吃到的能量球消失。教主不会轻功,教主不会二段跳,所以教主不能因新吃到的能量而变化此次跳跃的高度。并且教主还是生活在地球上的,所以教主每次跳完都会掉下来。
问教主若要吃完所有的能量球,最多还能保留多少能量。
 
 对于10%的数据,有N≤10;
 对于20%的数据,有N≤100;
 对于40%的数据,有N≤1000;
 对于70%的数据,有N≤100000;
 对于100%的数据,有N≤2000000。
 保证对于所有数据,教主都能吃到所有的能量球,并且能量球包含的能量之和不超过2^31-1。

题解:

这题我们设f[i]表示跳完了前I所保留的最大能量
不难推出转移:
f[i]=max{f[j]+sum[I]-sum[j]-I*100}
没错时间复杂度是O(n^2)的!
所以肯定会TLE
我们要优化,因为转移时候,我们只需要找到f[j]-sum[j]的最大值转移过来就可以了,所以用单调队列
维护一下就可以了

时间复杂度:O(N)

代码:

var
       cmax,sum,f:array [0..2000001] of longint;
       head,tail,i,j,k,n,m,x:longint;

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

begin
       readln(n,f[0]);
       cmax[1]:=0;
       head:=1;
       tail:=1;
       for i:=1 to n do
         begin
               read(x);
               sum[i]:=sum[i-1]+x;
               while (head<=tail) and (f[cmax[head]]<i*100) do inc(head);
               f[i]:=f[cmax[head]]+sum[i]-sum[cmax[head]]-i*100;
               k:=f[i]-sum[i];
               while (head<=tail) and (f[cmax[tail]]-sum[cmax[tail]]<=k) do dec(tail);
               inc(tail);
               cmax[tail]:=i;
         end;
       writeln(f[n]);
end.
阅读更多

没有更多推荐了,返回首页