写下单调队列思路怕自己忘
计算区间和的问题,一般转换为两个前缀和相减,所以我们先求出前缀和sum[i]
表示前i
项的和,那么就转化成了求 $s[r]-s[l-1]$
枚举右端点,则问题变为:找到一个左端点, $i−m<=j<=i−1$ 且 $s[j]$ 最小
然后执行单调队列的几个步骤:
-
判断队首与i的距离是否超过M的范围,若超出则弹
-
更新答案,因为此时队首就是右端点为
i
时,左端点j
最佳选择 -
不断删除队尾,直到队尾的
sum
小于sum[i]
,然后将i
入队#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define re register int #define ll long long #define maxn 300005 using namespace std; int a[maxn], q[maxn], sum[maxn]; int l, r; int n, m; int main() { scanf("%d%d", &n, &m); for (re i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i]; l = 1, r = 1; q[1] = 0; int ans = -0x3f3f3f3f; for (re i = 1; i <= n; i++) { while (l <= r && q[l] < i - m) l++; ans = max(ans, sum[i] - sum[q[l]]); while (l <= r && sum[q[r]] >= sum[i]) r--; q[++r] = i; } printf("%d ", ans); return 0; }