参考大佬(8条消息) C++题解:最大子序和——单调队列求滑动窗口最值_极客少年-CSDN博客
算法思想(前缀和+单调队列求滑动窗口最值)
1.最优化问题
最优化问题一般可以描述为在一个 有限集合 中求 最值 ,或者是方案数。
那么实际可以从集合的角度,分析最优化问题。
2.
对于本题来说,可以将长度为n的整数序列中所有长度不超过m的连续子序列看作一个全集,要求的是在这个全集中找到一个连续子序列和最大的序列。
在求解之前需要将集合分类,可以根据序列中最后一个数在整数序列中的位置将集合划分成若干个子集。
以a[k]
结尾的子序列为例求该类的最大值:
所有长度为j(1 ≤ j ≤ m 1\le j\le m1≤j≤m)的连续子序列的和,都可以表示为s[k] - s[k - j]。其中s[k]是固定的,那么求最大值,只需要求k之前大小为m的区间中一个最小的s[i]即可。
这样本题可以转换为长度为m的滑动窗口求最小前缀和问题,可以使用单调上升队列优化。
这是洛谷滑动窗口模板题P1886 滑动窗口 /【模板】单调队列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
下面为代码
#include<cstdio> #include<cstdlib> #include<queue> using namespace std; int n,k; const int N=1000003; struct node { int h,v; }p[N]; int ans[N][2]; deque <node> q1,q2;//最大,最小 int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&p[i].v ); p[i].h =i; int t=i -k+1; while(!q1.empty() && p[i].v >=q1.back().v ) q1.pop_back() ;//小于则删除 while(!q1.empty() && t >q1.front().h ) q1.pop_front() ;//过时则删除 q1.push_back(p[i]); while(!q2.empty() && p[i].v <=q2.back().v) q2.pop_back() ; while(!q2.empty() && t >q2.front().h ) q2.pop_front() ; q2.push_back(p[i]); ans[i][0]=q1.front() .v; ans[i][1]=q2.front() .v; } for(int i=k;i<=n;i++) printf("%d ",ans[i][1]); printf("\n"); for(int i=k;i<=n;i++) printf("%d ",ans[i][0]); return 0; }