码迷,mamicode.com
首页 > 其他好文 > 详细

最大子序和

时间:2020-03-15 09:30:35      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:namespace   长度   更新   需要   要求   连续   下标   main   col   

# 题意
长度为n的整数序列,从中找出一段长度不超过m的连续子序列,使得子序列中所有数的和最大

# 题解
区间和问题,转化为两个前缀和相减的形式进行求解。
枚举右端点
贪心法求解,只需要对下标和前缀应用单调队列,在队列中下标位置递增,前缀和s也递增,
假如右端点r固定,找到一个左端点ll,要求j∈[i−m,i−1]
s[j]要尽量的小,为了使得区间和最大
j的取值,是一个区间,我们只要这个区间的最值。
区间最值,就可以通过单调队列处理。
我们发现如果说有一个位置k,k<j<i.而且sum[k]≥sum[j]
那么sum[i]−sum[k] <= sum[i]−sum[j],也就是说我们的 j 更靠近 i ,不易超过限制m,并且答案更优,那么k是没有用了。

所以每次更新的时候先把越界的队头去除,剩下的显然就是最优解
队列中存的是下标,而且值也是单调上升的,如果值比当前右端点大显然后面不会用到
所以一直累加即可 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=3e5+10;
 4 int q[N],h=1,t=1;
 5 int a[N],s[N];
 6 int n,m;
 7 int main(){
 8    cin>>n>>m;
 9    for(int i=1;i<=n;i++)
10    {
11       cin>>a[i];
12       s[i]=s[i-1]+a[i];
13    }
14    int ans=INT_MIN;
15    q[1]=0;
16    for(int i = 1;i<=n;i++)
17    {
18       while(h<=t && q[h] < i - m + 1) h++;
19       ans=max(ans,s[i] - s[q[h]]);
20 
21       while(h<=t && s[i] <= s[q[t]])
22          t--;
23 
24       q[++t]=i;
25    }
26    cout<<ans;
27 }

 

最大子序和

标签:namespace   长度   更新   需要   要求   连续   下标   main   col   

原文地址:https://www.cnblogs.com/hhyx/p/12495725.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!