其他分享
首页 > 其他分享> > cf1667 B. Optimal Partition

cf1667 B. Optimal Partition

作者:互联网

题意:

把数组分为任意子段。对每个子段,若子段和为正,则其价值为子段长度;若为负则为子段长度的相反数;若为0则价值为0。求最大价值总和。

思路:

若 \(a_i\le 0\),那不如 \(a_i\) 自成一段,长度为 1。

dp。两种选择:

\(dp(i)=dp(i-1)+ sgn(a_i)\)

\(dp(i) = i + \max\limits _{s_i>s_j} \{-j+dp(j)\}\)

对于第二种,把 \(s[]\) 离散化后用树状数组维护前缀最大值

注意细节:树状数组要初始化为负无穷,ask() 函数也要负无穷。\(s_0\) 也要算上

void sol() {
    cin >> n; for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) s[i] = s[i-1] + a[i];
    //离散化,注意要把0算上
    vector<ll> ALL(s,s+1+n); sort(all(ALL)), ALL.erase(unique(all(ALL)), ALL.end());
    for(int i = 0; i <= n; i++) ord[i] = lower_bound(all(ALL),s[i])-ALL.begin()+1;
    //dp,记得0
    fill(tr, tr + 1 + n, -INF); add(ord[0], 0);
    for(int i = 1; i <= n; i++) {
        f[i] = f[i-1] - (a[i] < 0) + (a[i] > 0);
        f[i] = max(f[i], ask(ord[i]-1) + i);
        add(ord[i], f[i] - i);
    }    
    cout << f[n] << endl;
}

标签:cf1667,段长度,int,max,Partition,数组,ask,Optimal,dp
来源: https://www.cnblogs.com/wushansinger/p/16218036.html