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