【題解】P1440 求m區間內的最小值

求m區間內的最小值

題目描述ios

一個含有n項的數列(n<=2000000),求出每一項前的m個數到它這個區間內的最小值。若前面的數不足m項則從第1個數開始,若前面沒有數則輸出0。ui

分析:

讀題以後能夠發現,這道題就是在求:spa

給出一個長度爲n的序列A,求A中全部長度爲m的連續子序列中的最小值code

而針對這種問題,單調隊列彷佛是咱們最好的選擇。blog

單調隊列,說是隊列,卻不符合隊列「先進先出」的原則,它只是沿用了隊列的思想,並具備必定的單調性,擁有一個隊列頭head和一個隊列尾tail,用headtail來控制隊列的長度,篩選隊列中的元素以及保持隊列的單調性隊列

但怎樣控制隊列的長度,篩選隊列中的元素以及保持隊列的單調性呢?get

這就是單調隊列的實現了。io

用樣例來分析一下:class

6 2
7 8 1 4 3 2

這樣,咱們就擁有了一個初始隊列:7 8 1 4 3 2stream

擁有上帝視角的咱們能夠看出答案是:

0
7
7
1
1
3

這時候,咱們發現,不論第一個元素是多少,它以前m個元素的最小值永遠爲0(由於它以前並無元素)​,而最後一個元素是多少也沒有關係(由於它以後並無元素)

因此咱們只用找到第2個到第n個元素中每一個前m個元素的最小值就能夠了,那麼單調隊列的單調性也應該是遞增的,咱們就能夠把隊列裏每一個元素的序號放入單調隊列操做,就能夠獲得答案了。

因而咱們能夠開始模擬了:

考慮第一個元素,i=1,head=1,tail=0,q[tail]=0,a[1]=7,a[1]>a[ q[tail] ],把a[1]放入不會破壞單調性,q[head]=0,這個元素距隊首元素的距離爲0,則隊列爲:1

考慮第二個元素,i=2,head=1,tail=1,q[tail]=1,a[2]=8,a[2]>a[ q[tail] ],把a[2]放入不會破壞單調性,q[head]=1,這個元素距隊首元素的距離爲1,則隊列爲:1 2

考慮第三個元素,i=3,head=1,tail=2,q[tail]=2,a[3]=1,但a[3]<a[ q[tail] ],把a[3]放入會破壞單調性,而a[3]<a[ q[tail] ],因爲求最小值,因此只能將a[ q[tail=2] ]彈出隊列來保證單調性了,而a[3]>a[ q[tail=1] ],這時再將a[3]放入就不會破壞單調性了,q[head]=1,這個元素距隊首元素的距離爲2,達到長度m=2了,這隊列頭head就向後移,則隊列爲:3。

以此類推,直到第n-1個,由於第n個後面沒有元素,因此第n個不會進入隊列,每次都輸出隊列頭對應的元素值,就獲得了答案。

代碼實現:

#include <iostream>
#include <cstdio>
#include <cmath>
#define maxn 2000005
using namespace std;
int n,m;
int a[maxn];
int q[maxn];
int head,tail;
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    head=1;
    tail=0;
    printf("0\n");//第一個元素它以前並無元素
    for(int i=1;i<n;i++)//從1~n-1個,第n個不進隊列
    {
        while((head<=tail)&&((i-q[head])>=m)) head++;//控制隊列的長度
        while((head<=tail)&&(a[q[tail]]>=a[i])) tail--;//篩選隊列中的元素
        tail++;
        q[tail]=i;//保持隊列的單調性
        printf("%d\n",a[q[head]]);//輸出答案
    }
    return 0;
}
相關文章
相關標籤/搜索