题解 | 《算法竞赛进阶指南》最大子序和

【题目】

输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。
例如 1,-3,5,1,-2,3
当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6

【题解】

一开始没有想到可以用单调队列,以为能用dp之类的过过掉,但是莫得成功,寻思之后再想想。而单调队列的做法,其实原理很简单,便是算出N个数的前缀和 a n s [ 1 ] , a n s [ 2 ] a n s [ N ] ans[1],ans[2] \dots ans[N] ,设要求出的最大连续子序列和是 a n s [ y ] a n s [ x ] ans[y]-ans[x] ,我们要做的就是让这个 a n s [ y ] a n s [ x ] ans[y]-ans[x] 差值最大,而要最大,则需要使 a n s [ y ] ans[y] 尽可能的大, a n s [ x ] ans[x] 尽可能的小,而 y y 可以不用管,我们可以用把N个数枚举过去来实现,只需要找出枚举过程中的 i i 前面最小的 a n s [ ] ans[?] ,并且要使当中的数的数量不超过m。到这里,就可以想到用单调队列来实现找出所需的最小值。然后找出所有的 a n s [ i ] ans[i] 的值减去最优的最小值的差值最大的值即可。

时间复杂度: O ( N ) O(N)

#include<iostream>
#include<cstring>
#include<sstream>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<set>
#include<map>
#include<algorithm>
#define fi first
#define se second
#define MP make_pair
#define P pair<int,int>
#define PLL pair<ll,ll>
#define lc (p<<1)  
#define rc (p<<1|1)
#define MID (tree[p].l+tree[p].r)>>1
#define Sca(x) scanf("%d",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)
#define Scl2(x,y) scanf("%lld%lld",&x,&y)
#define Scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define Pri(x) printf("%d\n",x)
#define Prl(x) printf("%lld\n",x)
#define For(i,x,y) for(int i=x;i<=y;i++)
#define _For(i,x,y) for(int i=x;i>=y;i--)
#define FAST_IO std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define STOP system("pause")
#define ll long long
const int INF=0x3f3f3f3f;
const ll INFL=0x3f3f3f3f3f3f3f3f;
const double Pi = acos(-1.0);
using namespace std;
template <class T>void tomax(T&a,T b){ a=max(a,b); }  
template <class T>void tomin(T&a,T b){ a=min(a,b); }
const int N=3e5+5;
int num[N],sum[N];
list<int> q;
int main(){
	int n,m; Sca2(n,m);
	For(i,1,n){
		Sca(num[i]);
		sum[i]=sum[i-1]+num[i];
	}
	int maxx=0;
	q.push_back(0);
	For(i,1,n){
		while(!q.empty() && sum[i]<sum[q.back()]) q.pop_back();
		q.push_back(i);
		while(!q.empty() && i-q.front()>m) q.pop_front();
		tomax(maxx,sum[i]-sum[q.front()]);
	}
	Pri(maxx);
}
发布了39 篇原创文章 · 获赞 9 · 访问量 1958

猜你喜欢

转载自blog.csdn.net/qq_36296888/article/details/103057784