AcWing:135. 最大子序和(前缀和 + 单调队列)
输入一个长度为n的整数序列,从中找出一段长度不超过m的连续子序列,使得子序列中所有数的和最大。
输入格式
第一行输入两个整数n,m。
第二行输入n个数,代表长度为n的整数序列。
同一行数之间用空格隔开。
输出格式
输出一个整数,代表该序列的最大子序和。
数据范围
1≤n,m≤3000001≤n,m≤300000
输入样例:
6 4
1 -3 5 1 -2 3
输出样例:
7
算法:前缀和 + 单调队列
注意:单调队列需要使用双端队列deque,因为其中需要头部弹出以及尾部弹出。
#include <iostream> #include <cstdio> #include <deque> using namespace std; #define INF 0x3f3f3f3f const int maxn = 3e5+7; deque<int> que; int arr[maxn]; int sum[maxn]; int main() { int n, m; scanf("%d %d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &arr[i]); sum[i] = sum[i - 1] + arr[i]; } int ans = -INF; for(int i = 1; i <= n; i++) { while(!que.empty() && i - que.front() > m) { //如果队列里面的数超过了m的话,就将前面的弹出 que.pop_front(); } int k; if(que.size() > 0) { k = que.front(); } else { k = 0; } ans = max(ans, sum[i] - sum[k]); while(!que.empty() && sum[que.back()] >= sum[i]) { //利用前缀和来维护单调队列,根据前缀和的性质, que.pop_back(); } que.push_back(i); } cout << ans << endl; return 0; }