【题目】

输入一个长度为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个数的前缀和,设要求出的最大连续子序列和是,我们要做的就是让这个差值最大,而要最大,则需要使尽可能的大,尽可能的小,而可以不用管,我们可以用把N个数枚举过去来实现,只需要找出枚举过程中的前面最小的,并且要使当中的数的数量不超过m。到这里,就可以想到用单调队列来实现找出所需的最小值。然后找出所有的的值减去最优的最小值的差值最大的值即可。

时间复杂度:

#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);
}