【牛客小白月赛16】D 小阳买水果
题意:
有一个序列\(a_i\),要求选一段区间,使得区间和大于\(0\),问最长区间是多少。
思路:
考虑枚举区间的右端点,相当于要找一个最左的左端点,使得区间和大于\(0\),写成前缀和的形式即为\(sum[r] - sum[l - 1] > 0\)。
那么我们把前缀和放入单调队列,能入队的话相当于当前点的\(sum[x]\)小于队尾的,因为如果大于的话,那么取队尾肯定是更优的,然后再单调队列上二分即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define N 2000010
#define pii pair <int, int>
#define fi first
#define se second
int n, a[N];
pii q[N]; int last;
int main() {
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
a[i] += a[i - 1];
}
for (int i = 1; i <= n; ++i) a[i] *= -1;
int res = 0;
last = 0;
q[++last] = pii(0, 0);
for (int i = 1; i <= n; ++i) {
int pos = lower_bound(q + 1, q + 1 + last, pii(a[i] + 1, 0)) - q;
if (pos <= last) {
res = max(res, i - q[pos].se);
}
if (a[i] > q[last].fi) q[++last] = pii(a[i], i);
}
printf("%d\n", res);
}
return 0;
}