link
#782 div.2
2100, 树状数组优化dp,离散化
题意
给你一个数组,要求你分成若干个连续的子数组,每个子数组的价值为:
- 若子数组数字和为正数,价值为数组长度
- 和为0,价值为0
- 和为负数,价值为数组长度 * -1
求子数组价值和最大值。 n ≤ 5 e 5 , − 1 e 9 ≤ a i ≤ 1 e 9 n \leq 5e5, -1e9\leq a_i\leq 1e9 n≤5e5,−1e9≤ai≤1e9
思路
设
v
a
l
i
,
j
val_{i, j}
vali,j 表示数组第
i
i
i 到第
j
j
j 项的价值,
d
p
i
dp_i
dpi 表示前
i
i
i 个数字的价值和最大值。则
d
p
i
=
max
0
≤
j
<
i
{
d
p
j
+
v
a
l
j
+
1
,
i
}
dp_i = \max_{0\leq j < i}\{ dp_j + val_{j+1, i}\}
dpi=max0≤j<i{dpj+valj+1,i},可以在
O
(
n
2
)
O(n^2)
O(n2) 内转移。
考虑用树状数组优化,存入
d
p
i
+
i
dp_i + i
dpi+i
代码
int a[maxn];
int C[maxn], n, m;
int sum[maxn], dp[maxn], ls[maxn];
int lowbit(int x) {
return x & -x;
}
void update(int x, int d) { //第x组加d
while(x <= maxn) {
C[x] = max(C[x], d);
x += lowbit(x);
}
}
int ask(int x) { //前x组的和
int ret = -INF;
while(x > 0) {
ret = max(ret, C[x]);
x -= lowbit(x);
}
return ret;
}
void solve() {
cin >> n;
for(int i = 1; i <= n; i++) {
dp[i] = C[i] = -INF;
ls[i] = -1;
}
for(int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = a[i] + sum[i-1];
}
vector<int> cur;
for(int i = 0; i <= n; i++) {
cur.push_back(sum[i]);
}
sort(cur.begin(), cur.end());
for(int i = 0; i <= n; i++) {
sum[i] = lower_bound(cur.begin(), cur.end(), sum[i]) - cur.begin() + 1;
}
update(sum[0], dp[0]);
ls[sum[0]] = 0;
for(int i = 1; i <= n; i++) {
dp[i] = dp[i-1];
if(a[i] < 0) {
dp[i]--;
}
dp[i] = max(dp[i], ask(sum[i] - 1) + i);
if(ls[sum[i]] != -1) {
dp[i] = max(dp[i], dp[ls[sum[i]]]);
}
update(sum[i], dp[i] - i);
ls[sum[i]] = i;
}
cout << dp[n] << endl;
for(int i = 0; i <= n; i++) {
a[i] = sum[i] = dp[i] = C[i] = 0;
}
}