【演算法競賽進階指南】單調佇列CH1201最大子序列和
阿新 • • 發佈:2018-12-07
輸入一個長度為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; }