单调队列(oj1771)

先看道题
这里写图片描述

很显然,这题可以用堆去做。解法具体可以去看我以前写的博客

然而这不是重点。。。

重点是写一个堆太eggache了
有没有其它办法?

那就是单调队列


设一个单调递增队列d

何为递增?
后面的数一定比前面的小

先不管怎么实现,如果一直维护着一个单调队列,那么它的头元素一定是最小/大的。
因为它是队列里最小/大的数啊。。


那么问题来了
怎么维护

主要是插入元素
因为要维护单调的性质,所以如果当前的元素和尾元素产生冲突(大/小)时,
就把尾元素丢掉
当然如果整个队列都被扔了,那么新元素就是头元素

关于查找

有时候题目会加上一些奇怪的性质(比如烽火传递),有时候头元素不能用
那么就直接丢掉,直到能用为止

代码

var
        a:array[1..100000] of longint;
        f:array[1..100000] of longint;
        d:array[1..100000,1..2] of longint;
        n,m,i,h,t,ans:longint;
procedure put(s,s2:longint);
var
        i:longint;
begin
        while (h<=t) and (d[t,1]>=s) do
        dec(t);
        inc(t);
        d[t,1]:=s;
        d[t,2]:=s2;
end;
function min(x,y:longint):longint;
begin
        if x<y then min:=x
        else
        min:=y;
end;
procedure swap(var x,y:longint);
var
        z:longint;
begin
        z:=x;
        x:=y;
        y:=z;
end;
procedure qsort(l,r:longint);
var
        i,j,mid:longint;
begin
        i:=l;
        j:=r;
        mid:=d[(l+r) div 2,1];
        while i<=j do
        begin
                while (d[i,1]<mid) do inc(i);
                while (d[j,1]>mid) do dec(j);
                if i<=j then
                begin
                        swap(d[i,1],d[j,1]);
                        swap(d[i,2],d[j,2]);
                        inc(i);
                        dec(j);
                end;
        end;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
end;
begin
        assign(Input,'beacon.in'); reset(Input);
        assign(Output,'beacon.out'); rewrite(Output);
        readln(n,m);
        for i:=1 to n do
        readln(a[i]);
        for i:=1 to m do
        begin
                f[i]:=a[i];
                d[i,1]:=a[i];
                d[i,2]:=i;
        end;
        h:=1;
        t:=m;
        qsort(1,t);
        for i:=m+1 to n do
        begin
                while (h<=t) and (d[h,2]+m<i) do
                inc(h);
                f[i]:=d[h,1]+a[i];
                put(f[i],i);
        end;
        ans:=maxlongint;
        for i:=n-m+1 to n do
        ans:=min(ans,f[i]);
        writeln(ans);
        close(Input); close(Output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值