codeforces round#783 div2 D

codeforces round#783 div2 D

思路:

首先考虑前缀和为负数和0,肯定是每次只考虑一个数字最优;
然后考虑dp f[i]=max(f[j]+i-j),其中j+1到i的和为正数,
就是在前i个里找前缀和小于si并且最大的f[j],因为f[j]中j已经选择,
所以是j+1到i,使用树状数组维护前缀和就可以查询,更新的时候可以
赋值为f[j]-j,这样求出来的最大值再加i就是f[i]

代码:

const int N = 500010;
int c[N];
int  ask(int x) {
    int res = -inf;
    for (;x;x -= lowbit(x)) res = max(res, c[x]);
    return res;
}
void add(int x, int y) {
    for (;x < N;x += lowbit(x)) c[x] = max(c[x], y);
}
int f[N], a[N], s[N];
vector<int> v;
int find(int x) {
    return lower_bound(all(v), x) - v.begin() + 1;
}
void solve() {
    int n = read();
    v.clear();
    for (int i = 1;i <= n;i++) a[i] = read(), s[i] = s[i - 1] + a[i], v.push_back(s[i]);
    sort(all(v));
    v.erase(unique(all(v)), v.end());
    for (int i = 0;i <= n + 10;i++) c[i] = -inf;
    int ans = 0;
    f[0] = 0;
    for (int i = 1;i <= n;i++) f[i] = -inf;
    for (int i = 1;i <= n;i++) {
        int x = find(s[i]);
        int t = ask(x - 1);
        int val = 0;
        if (a[i] > 0) val = 1;
        else if (a[i] == 0) val = 0;
        else val = -1;
        int d = -inf;
        if (s[i] > 0) d = i;
        f[i] = max({ f[i - 1] + val, t + i,d });
        add(x, f[i] - i);
    }
    printf("%lld\n", f[n]);
    clean();
}
posted @ 2022-04-20 13:25  指引盗寇入太行  阅读(42)  评论(0编辑  收藏  举报