輸入乙個長度為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...