單調佇列詳解

2021-10-19 08:12:42 字數 4916 閱讀 5083

剛學單調佇列時,在網上各大部落格找文章學,說實話,寫得很雜,表示自己懵逼了些許,最後硬是啃出來了,所以我決定要寫一篇能讓大部分人都看懂的部落格來。

說單調佇列,那我們就先說說這個單調佇列是個什麼物種。單調佇列從字面上看,無非就是有某種單調性的佇列,沒錯,這就是所謂的單調佇列。 單調佇列它分兩種,一種是單調遞增的,另外一種是單調遞減的。

用單調佇列來解決問題,一般都是需要得到當前的某個範圍內的最小值或最大值。

舉個例子:有  7 6 8 12 9 10 3 七個數字,現在讓你找出範圍( i-4,i ) 的最小值。

那我們就可以這樣模擬一遍。

先初始化 (表示i=0時的值)

i=1 -> (表示i=1,時,在其範圍內最小的值為0)-> 7進隊 ;

i=2->(表示i=2,時,在其範圍內最小的值為7)-> 6比7小,7出,6進 ;

i=3->  (表示i=3,時,在其範圍內最小的值為6)->8比6大,8進  ;

i=4->(表示i=4,時,在其範圍內最小的值為6)-> 12比8大,12進 ;

i=5-> (表示i=4,時,在其範圍內最小的值為6)-> 9比12小,12out,9比8大,9進 ;

i=6->  但是 單調佇列中元素6的下標是2,不在(2, 6],中,故6 out,這就是單調佇列的精髓了。故單調隊列為

(表示i=5,時,在其範圍內最小的值為8)->10比9大,10進 最終 單調隊列為 ;

i=7->(表示i=6,時,在其範圍內最小的值為8)-> 3比單調隊列為 的任意值都小,故全out,最終集合為 ;

相信大家看完這個例子了解得有些吧,再次重申一遍,單調佇列的核心(我認為的哈):得到當前的某個範圍內的最小值或最大值。要不是這樣的話,那還有必要這麼麻煩找嗎,直接找前面最小的就好了,可事實不是這樣,題目是有限制的,規定在某個範圍內找。

那我們就來看到例題,加深理解:

description

乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。

例如:  1, -3, 5, 1, -2, 3

當m=4時,sum =  5+1-2+3 = 7

當m=2或m=3時,sum = 5+1 = 6

input

多測試用例,每個測試用例:

第一行是兩個正數n, m  ( n, m ≤ 300000 )

第二行是n個整數

output

每個測試用例輸出一行:乙個正整數,表示這n個數的最大子序和長度

sample input

6 41 -3 5 1 -2 3

sample output

這題可以用dp來解,在這我們就用單調佇列來解。

我們先把序列的前i項和加起來並存到乙個陣列sum[ ]上,那麼任意連續的子串行和就為sum [ i ] - sum[ j ] (i>j &&  j>i-m)。

那麼我們就可以跟上述例子一樣,一直更新就好了,每次找出在(i-m,i)範圍內的最小sum[j]值。

**一:

#include

#include

///單調佇列,

#include

#include

using

namespace std;

typedef

long

long ll;

const

int maxn=

300010

;ll sum[maxn]

;list <

int> que;

intmain()

///初始化

ll maxs=sum[1]

; que.

push_front(1

);for(

int i=

2;i<=n;i++

)printf

("%lld\n"

,maxs);}

return8;

}

**二:

#include

///單調遞增序列(但保證最可能小)

#include

#include

using

namespace std;

typedef

long

long ll;

const ll maxn=

300010

;ll sum[maxn]

;ll index1[maxn]

;///儲存下標

intmain()

///初始化

int left=

1,right=1;

index1[1]

=1; ll tmax=sum[1]

;for

(int i=

2;i<=n;i++

)printf

("%lld\n"

,tmax);}

return0;

}

剛學單調佇列時,在網上各大部落格找文章學,說實話,寫得很雜,表示自己懵逼了些許,最後硬是啃出來了,所以我決定要寫一篇能讓大部分人都看懂的部落格來。

說單調佇列,那我們就先說說這個單調佇列是個什麼物種。單調佇列從字面上看,無非就是有某種單調性的佇列,沒錯,這就是所謂的單調佇列。 單調佇列它分兩種,一種是單調遞增的,另外一種是單調遞減的。

用單調佇列來解決問題,一般都是需要得到當前的某個範圍內的最小值或最大值。

舉個例子:有  7 6 8 12 9 10 3 七個數字,現在讓你找出範圍( i-4,i ) 的最小值。

那我們就可以這樣模擬一遍。

先初始化 (表示i=0時的值)

i=1 -> (表示i=1,時,在其範圍內最小的值為0)-> 7進隊 ;

i=2->(表示i=2,時,在其範圍內最小的值為7)-> 6比7小,7出,6進 ;

i=3->  (表示i=3,時,在其範圍內最小的值為6)->8比6大,8進  ;

i=4->(表示i=4,時,在其範圍內最小的值為6)-> 12比8大,12進 ;

i=5-> (表示i=4,時,在其範圍內最小的值為6)-> 9比12小,12out,9比8大,9進 ;

i=6->  但是 單調佇列中元素6的下標是2,不在(2, 6],中,故6 out,這就是單調佇列的精髓了。故單調隊列為

(表示i=5,時,在其範圍內最小的值為8)->10比9大,10進 最終 單調隊列為 ;

i=7->(表示i=6,時,在其範圍內最小的值為8)-> 3比單調隊列為 的任意值都小,故全out,最終集合為 ;

相信大家看完這個例子了解得有些吧,再次重申一遍,單調佇列的核心(我認為的哈):得到當前的某個範圍內的最小值或最大值。要不是這樣的話,那還有必要這麼麻煩找嗎,直接找前面最小的就好了,可事實不是這樣,題目是有限制的,規定在某個範圍內找。

那我們就來看到例題,加深理解:

description

乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。

例如:  1, -3, 5, 1, -2, 3

當m=4時,sum =  5+1-2+3 = 7

當m=2或m=3時,sum = 5+1 = 6

input

多測試用例,每個測試用例:

第一行是兩個正數n, m  ( n, m ≤ 300000 )

第二行是n個整數

output

每個測試用例輸出一行:乙個正整數,表示這n個數的最大子序和長度

sample input

6 41 -3 5 1 -2 3

sample output

這題可以用dp來解,在這我們就用單調佇列來解。

我們先把序列的前i項和加起來並存到乙個陣列sum[ ]上,那麼任意連續的子串行和就為sum [ i ] - sum[ j ] (i>j &&  j>i-m)。

那麼我們就可以跟上述例子一樣,一直更新就好了,每次找出在(i-m,i)範圍內的最小sum[j]值。

**一:

單調佇列詳解

剛學單調佇列時,在網上各大部落格找文章學,說實話,寫得很雜,表示自己懵逼了些許,最後硬是啃出來了,所以我決定要寫一篇能讓大部分人都看懂的部落格來。說單調佇列,那我們就先說說這個單調佇列是個什麼物種。單調佇列從字面上看,無非就是 有某種單調性 的佇列,沒錯,這就是所謂的單調佇列。單調佇列 它分兩種,一...

單調棧 單調佇列詳解

首先看乙個問題。給定乙個數列,從左至右輸出每個長度為 k 的數列段內的最小數和最大數 第一行輸出每個區間最小值,第二行輸出最大值 數列長度 n leq 10 6 k leq n 解法 很直觀的一種解法,那就是從數列的開頭,找到這最開始的k個數的最大值,然後後移乙個單元,繼續找到k個數中的最大值。這種...

dp單調佇列(詳解)

我們從最簡單的問題開始 給定乙個長度為n的整數數列a i i 0,1,n 1和窗長度k.要求 f i max,i 0,1,n 1 問題的另一種描述就是用乙個長度為k的窗在整數數列上移動,求窗裡面所包含的數的最大值。解法一 很直觀的一種解法,那就是從數列的開頭,將窗放上去,然後找到這最開始的k個數的最...