1. 程式人生 > 其它 >codeforces round#783 div2 D

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();
}