1. 程式人生 > >【演算法競賽進階指南】單調佇列CH1201最大子序列和

【演算法競賽進階指南】單調佇列CH1201最大子序列和

輸入一個長度為n的整數序列,從中找出一段不超過m的連續子序列,使得整個序列的和最大。
下標位置遞增、對應的字首和S的值也遞增的序列為最優的選擇策略
我們掃描i,對i進行如下操作
1.判斷隊頭與i的距離與m的關係來決策是否出隊
2.更新答案
3.刪除隊尾決策使整個佇列單調

n=6 m=4
輸入資料:1 -3 5 1 -2 3
字首和:1 -2 3 4 2 5
0 1
-2(-2之後用不到1,因為無論如何某個數+2比-1大)
-2 3
-2 3 4
-2 2(3和4也用不到,佇列單調可以保證)
-2 2 5
7
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int s[300005],q[300005];

int main(){
    memset(s,0,sizeof(s));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&s[i]);
        s[i]+=s[i-1];
    }
    //for(int i=1;i<=n;i++) cout<<s[i]<<" ";
    //cout<<"\n";
    int l=1,r=1;
    q[1]=0;//save choice j;
    int ans=-0x3f3f3f;
    for(int i=1;i<=n;i++){
        while(l<=r && q[l]<i-m) l++;
        ans=max(ans,s[i]-s[q[l]]);
        while(l<=r && s[q[r]]>=s[i]) r--;
        q[++r]=i;
        //for(int k=l;k<=r;k++) cout<<s[q[k]]<<" ";
        //cout<<"\n";
    }
    printf("%d",ans);
    return 0;
}