1. 程式人生 > 其它 >CF783-D Optimal Partition

CF783-D Optimal Partition

Optimal Partition

// dp + fenwick + 離散 + 字首和
// 可以證明:對於最優劃分,分數為0和負數的區間一定可以優化成長度只有1的子段
// 現在只考慮分數為正數的情況:f[i] = max{f[j] - j} + i; 則維護一棵Fenwick Tree即可
// f[i] = max(f[i - 1] + (a[i] < 0 ? -1 : 0), fen.sum(s[i]));
#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int INF = 1e9;

struct Fenwick {
    const int n;
    std::vector<int> a;
    Fenwick(int n) : n(n), a(n, -INF) {}
    void add(int x, int v) {
        for (int i = x + 1; i <= n; i += i & -i) {
            a[i - 1] = std::max(a[i - 1], v);
        }
    }
    int sum(int x) {
        int ans = -INF;
        for (int i = x; i > 0; i -= i & -i) {
            ans = std::max(ans, a[i - 1]);
        }
        return ans;
    }
};

void solve(){
    int n; cin >> n;
    
    vector<int>a(n);
    for(int i = 0; i < n; ++i) cin >> a[i];
    
    vector<ll>s(n + 1);
    for(int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i - 1];
    
    auto v = s;
    sort(v.begin(), v.end());
    for(int i = 0; i <= n; ++i) s[i] = lower_bound(v.begin(), v.end(), s[i]) - v.begin();
    
    Fenwick fen(n + 1);
    vector<int>f(n + 1);
    for(int i = 1; i <= n; ++i) {
        fen.add(s[i - 1], f[i - 1] - i + 1);
        f[i] = max(f[i - 1] + (a[i - 1] < 0 ? -1 : 0), i + fen.sum(s[i]));
    }
    cout << f[n] << endl;
}

int main(){
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    
    int T; cin>>T;
    
    while(T--){
        solve();
    }
    return 0;
}