【牛客小白月赛16】D 小阳买水果

Practice Link

题意:
有一个序列\(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;
}
posted @ 2019-07-13 08:30  Dup4  阅读(379)  评论(0编辑  收藏  举报