【题目】
输入一个长度为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); }