【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;
#define rep(i,a,n) for(int i=a;i<n;i++)
const int N=3e5+10;
int s[N];
int n,m;
int ans=-1e9;
deque<int>q;
int main()
{
scanf("%d%d",&n,&m);
rep(i,1,n+1)
{
scanf("%d",&s[i]);
s[i] += s[i-1];
}
q.push_back(0);
rep(i,1,n+1)
{
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);
}