《演算法競賽高階指南》0x12 T4 最大子序和

2021-10-19 11:25:29 字數 2494 閱讀 7213

題目傳送門

輸入乙個長度為 n

nn 的整數序列,從中找出一段長度不超過 m

mm 的連續子串行,使得子串行中所有數的和最大。

注意:子串行的長度至少是 111。

第一行輸入兩個整數 n

nn ,mmm。

第二行輸入 n

nn 個數,代表長度為 n

nn 的整數序列。

同一行數之間用空格隔開。

輸出乙個整數,代表該序列的最大子序和。

1 11≤

\leq≤nn

n ,mmm≤

\leq

≤300000

300000

300000

6 41 -3 5 1 -2 3

演算法1:暴力列舉 o(n

m)

o(nm)

o(nm)

通過兩層迴圈列舉每乙個不超過m

mm的連續子串行

code

#include

using

namespace std;

const

int n=

3e5+10;

int n,m,a[n]

,maxn=-1

,sum=0;

intmain()

} cout

}

演算法2:字首和優化 o(n

m)

o(nm)

o(nm)

利用字首和解決演算法1中的sum

sumsu

m的累加過程

#include

using

namespace std;

const

int n=

3e5+10;

int n,m,a[n]

,s[n]

,maxn=-1

,sum=0;

intmain()

cout

}

演算法3:優先佇列優化 o(n

)o(n)

o(n)

假設ss

s陣列中的三個下標分別為 i,j

,k(k

<

j

i,j,k(ki,

j,k(

k<

j根據演算法2中的字首和優化,在 i

ii保持不變的情況下,s[i

]s[i]

s[i]

也保持不變,序列的中所有數的累加和為s[i

]−s[

left

]s[i]-s[left]

s[i]−s

[lef

t],所以s[l

eft]

s[left]

s[left

]越小,序列中的數字和就越大,也就更優。

那麼如果s[k

]≥s[

j]

s[k] \geq s[j]

s[k]≥s

[j]那k

kk一定是乙個無用的點,因為相比較而言,k

kk的位置以及s

ss陣列中的值都不如j

jj號點,所以k

kk就沒有任何價值

所以可以設計乙個演算法

用乙個佇列來模擬以下的操作,佇列儲存的是這個子序中每個元素的編號

從前向後遍歷,如果i

ii到隊首的元素編號q[h

ead]

q[head]

q[head

]超過了m

mm,就把隊首往後推

如果我當前這個元素的值要比隊尾的元素更優,即s[i

]

q[ta

il]]

s[i]s[

i]q[ta

il]]

(從前面的講解可知,元素的價值取決於它的位置和s

ss陣列中的值,因為是從前向後遍歷,所以當前位置一定比佇列中任何乙個數的位置更優,所以只需要比較s

ss陣列中的值)就將隊尾的元素刪去,並把這個元素塞到隊尾

由此可知,當前維護的佇列一定是乙個具有單調性的(從隊首到隊尾的元素均從大到小或從小到大),因此稱為單調佇列

最後不斷更新ans的值就可以啦

由於每個點都只會進出佇列一次,所以時間複雜度就是o(n

)o(n)

o(n)

#include

using

namespace std;

const

int n=

300010

;int a[n]

,s[n]

,q[n]

,head=

0,tail=0;

intmain()

for(

int i=

1;i<=n;i++

)printf

("%d"

,ans)

;return0;

}

演算法競賽高階指南 0x00

快速冪模板,寫一下快速冪的原理。我們知道,乙個數 n 在二進位制 也可以是其他進製 下可以被表示為 a 1 a 2 2 1 a 3 2 2 a m 2 那麼我們可以考慮將其分拆成二進位制狀態下的每一位,然後做冪運算。這樣做的時間複雜度為 o log 2 n 實現的過程類似於倒過來的分治 當然也可以直...

演算法競賽高階指南 0x12 最大子序和

這其實是一道單調佇列優化區間dp問題,對於這個序列,我們可以劃分為n個區間,每個區間代表以ai結尾,長度不超過m的子串行和,我們只需要遍歷一遍每個集合,找到每乙個集合中的最大值,那麼就可以更新出這個序列的最大值 如何找每個集合中的最大值呢,最大值就是要求出以a k 結尾,長度不超過m的子串行和最大,...

演算法競賽高階指南 0x12 佇列 蚯蚓

m次操作,每次都要將乙個最大的切成兩段,然後再加上乙個偏移量,然後將兩段全部放入佇列中,但是這樣是o mlogm 看題中資料範圍肯定會超時,那麼我就要繼續優化 我們可以發現,先將原序列從大到小排列 q1,q2,q3,q4 第一次肯定是切割q1,假設將q1切成了q1l,q1r,那麼對於第二次切割只需要...