1. 程式人生 > 實用技巧 >【k長度最大連續子序和】 最大子序和

【k長度最大連續子序和】 最大子序和

傳送門

題意

長度為\(n\)的整數序列,找出一段長度不超過\(m\)的和最大的連續子序列

資料範圍

\(1\leq n \leq 3·10^{5}\)

題解

  • 預處理字首和,貪心法,假如右端點\(i\)固定,找到一個左端點\(j \in [i-m,i-1]\)\(s_{j}\)要儘量的小,

  • 為了使得區間和最大,\(j\)的取值,是一個區間,我們只要這個區間的最值。區間最值,就可以通過單調佇列處理。

  • 如果有一個位置\(k\)\(k<j<i\).而且\(sum_{k}\geq sum_{j}\),那麼\(sum_{i}-sum_{k} \leq sum_{i} -sum_{j}\)

    • 也就是說\(j\)更靠近 \(i\) ,不易超過限制\(m\),並且答案更優,那麼\(k\)是沒有用了。所以每次更新的時候先把越界的隊頭去除,剩下的顯然就是最優解

Code

#include<bits/stdc++.h>
 
using namespace std;
const int N=3e5+10;
int s[N];
int n,m;
int ans=-1e9;
deque<int> q;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        s[i]=s[i-1]+x;
    }
     
    for(int i=1;i<=n;i++){
        while(q.size() && i-m>q.front()) q.pop_front();
        ans=max(ans,s[i]-s[q.front()]);
        while(q.size() && s[q.back()]>=s[i]) q.pop_back();
        q.push_back(i);
    }
    printf("%d",ans);
}