題目描述:ios
一個含有n項的數列(n<=2000000),求出每一項前的m個數到它這個區間內的最小值。若前面的數不足m項則從第1個數開始,若前面沒有數則輸出0。ui
讀題以後能夠發現,這道題就是在求:spa
給出一個長度爲n的序列A,求A中全部長度爲m的連續子序列中的最小值code
而針對這種問題,單調隊列彷佛是咱們最好的選擇。blog
單調隊列,說是隊列,卻不符合隊列「先進先出」的原則,它只是沿用了隊列的思想,並具備必定的單調性,擁有一個隊列頭head和一個隊列尾tail,用head和tail來控制隊列的長度,篩選隊列中的元素以及保持隊列的單調性。隊列
但怎樣控制隊列的長度,篩選隊列中的元素以及保持隊列的單調性呢?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; }