最大子序和 單調佇列

2021-09-16 22:08:21 字數 1297 閱讀 9409

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

輸入格式

第一行輸入兩個整數n,m。

第二行輸入n個數,代表長度為n的整數序列。

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

輸出格式

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

資料範圍

1≤n,m≤300000

輸入樣例:

6 4

1 -3 5 1 -2 3

輸出樣例:

7
題解參考李煜東的演算法競賽高階指南

用sum陣列儲存字首和,那麼區間和就轉化為兩個個字首和相減。

首先我們列舉右端點i,當i固定時,問題就變為:找到乙個左端點j,其中j屬於[j-m,i-m]並且是sum[j]最小。

不妨比較一下任意兩個位置j和k,如果k=sum[j],那麼對於所有大於等於i的右端點,k永遠不會成為最優選擇,這是因為不但sum[k]不小於sum[j],而且j離i更近,長度更不容易超過m,即j的生存能力比k更強。所以當j出現後,k是乙個完全無用的位置。

以上比較告訴我們,可能成為最優選擇的策略集合一點哪個是乙個「下標位置遞增,對應字首和sum的值也遞增」的序列。我們可以用乙個碎裂儲存這個序列。隨著右端點變從前向後掃瞄,我們對每個i執行以下三個步驟:

1.判斷對頭決策與i的距離是否超過m的範圍,若超出則出隊。

2.此時對頭就是右端點i時,左端點j的最優選擇。

3.不斷刪除隊尾決策,直到隊尾對應的sum值小於是sum[j].然後把i作為乙個新的決策入隊。

用q陣列模擬佇列,佇列裡存的是下標,head是隊頭,tail是隊尾。佇列裡的元素是單調遞增的。head對應的值最小

#include#includeusing namespace std;

const int maxn=3e5+5;

typedef long long ll;

int sum[maxn];

int q[maxn];

int main()

int head=1,tail=1;

q[head]=0;

int ans=sum[1];

for(int i=1;i<=n;i++)

cout

}

JOI(TYVJ)最大子序和 DP 單調佇列

輸入乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。例如 1,3,5,1,2,3 當m 4時,s 5 1 2 3 7 當m 2或m 3時,s 5 1 6 計算區間和的問題一般用字首和表示。先用s i 表示序列中前i項的和,然後s i s j 1 就可以表示i j的和 ...

單調佇列簡單應用 最大子序和

description 輸入乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。例如 1,3,5,1,2,3 當m 4時,s 5 1 2 3 7 當m 2或m 3時,s 5 1 6。input 第一行兩個數n,m n,m 300000 第二行有n個數,要求在n個數找到最大...

tyvj1305 最大子序和(單調佇列

時間限制 記憶體限制 評測方式 題目 1000ms 131072kib 標準比較器 local 輸入乙個長度為n的整數序列,從中找出一段不超過m的連續子串行,使得整個序列的和最大。例如 1,3,5,1,2,3 當m 4時,s 5 1 2 3 7 當m 2或m 3時,s 5 1 6 第一行兩個數n,m...