一本通#10176「一本通 5.5 例 2」最大连续和题解

题面:

题目描述

给你一个长度为 n 的整数序列,要求从中找出一段连续的长度不超过 m 的非空子序列,使得这个序列的和最大。

输入格式

第一行为两个整数 n,m;

第二行为 n 个用空格分开的整数序列,每个数的绝对值都小于 1000。

输出格式

仅一个整数,表示连续长度不超过 m 的最大非空子序列和。

样例

输入

6 4
1 -3 5 1 -2 3

输出

7

数据范围与提示
对于 \(50\%\) 的数据\(1\leq n\leq 10^4\)

对于 \(100\%\) 的数据,\(1\leq n\leq 10^5\)

题解

题目范围为\(1\)<=n<=\(10^5\)所以要O(N)的代码
我们从非空子序列和可以看出要有前缀和
设区间为[l,r]则区间和为sum[r]-sum[l-1]
我们把l固定下来则就要是sum[l-1]最小并且l-1要与r的距离不超过m(我代码中k是m)
那就会让人回想起优先队列滑动窗口求窗口内的最小值
我们这里把窗口大小设为m,求i(即区间的l)前使得sum[l-1]最小
然后就可以写代码了

样例代码有注释
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
int n,k,a[N],sum[N],dp[N],ans=INT_MIN;
deque<int> q;
int main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum[i]=sum[i-1]+a[i];
	}
	for(int i=1;i<=n;i++){
		while(!q.empty()&&q.front()<i-k) q.pop_front();//<i-k是特殊处理正常单调队列是<=i-k
		//这里特殊处理是因为19行 q.push_back(i-1); 因为我们要算前缀和所以-1但是我们只要区间
		//左端不与右端差超过k就行而 左端=q.front()+1,右端=i 所以条件是q.front()+1<=i-k即
		//q.front()<i-k
		while(!q.empty()&&sum[q.back()]>=sum[i-1]) q.pop_back();
		q.push_back(i-1);//19行特殊处理原因在上面 
		if(!q.empty()) ans=max(ans,sum[i]-sum[q.front()]);
	}
	cout<<ans;
	return 0;
}
做完试试 [另一道题题](http://noip.ybtoj.com.cn/contest/1091/problem/2) (这题的plus版)
posted @ 2025-08-28 16:04  linyide  阅读(7)  评论(0)    收藏  举报