问题 B: 最大子序和
题目描述
输入一个长度为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
第二行有n个数,要求在n个数找到最大子序和
输出
一个数,数出他们的最大子序和
样例输入 Copy
6 4
1 -3 5 1 -2 3
样例输出 Copy
7
提示
30%满足 n,m<=100
50%满足 n,m<=3000
100%满足n,m<=300000
-
思路分析:
单调队列
需要满足两个性质: -
队列内具有一定的单调性(优先队列)。
满足普通队列性质,一端进,另一端出,不可以中间插队。
但是这样就会现矛盾了,例如一个单调增的队列:1,5,8,9,我们要插入4,这时如果只能从尾端进去的话就打破了其单调性,呢么这时的做法就是从队尾到队头,把大于4的全部T了,然后插入后的队列就变成了1,4。 -
应用
常用于优化动态规划(DP)问题。
代码
#include<iostream>//线性筛素数
#include<math.h>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#define ll long long int
#define inf 0x3f3f3f3f
const int mod=998244353;
using namespace std;
const int maxn=300006;
ll n,q,m,t,p,l,r,sum,c[maxn];
ll a[maxn],b[maxn];
int main () {
cin>>n>>m;
b[0]=0;
for(int i=1; i<=n; i++) {
cin>>b[i];
b[i]+=b[i-1];
}
l = 1, r = 1, sum= -maxn;
c[1] = 0;
for (int i = 1; i <= n; i++) {
while (l <= r && c[l] < i - m) l++;
sum = max(sum, b[i] - b[c[l]]);
while (l <= r && b[c[r]] >= b[i]) r--;
c[++r] = i;
}
cout<<sum<<endl;
return 0;
}