比赛链接:

https://codeforces.com/contest/1667

B. Optimal Partition

题目大意:

长为 \(n\) 的序列 \(a\),将它分成若干段,对于 \(a_l, a_{l + 1}, ..., a_r\) 这一段,记 \(s = \sum_{i = l}^r a_i\)
\(s > 0\), 则这一段的值为 \((r - l + 1)\)
\(s = 0\), 则值为 0;
\(s < 0\), 则值为 \(-(r - l + 1)\)
求出分段后能取得的最大价值。

思路:

先考虑 \(O(n^2)\)暴力做法。
定义 \(f[i]\) 为从 1 到 \(i\) 这一段划分后的最大价值,\(s[i]\) 为从 1 到 \(i\) 这一段的前缀和。
定义 \(k\) 如下:
\(s[i] > s[j]\)\(k = 1\)
\(s[i] = s[j]\)\(k = 0\)
\(s[i] < s[j]\)\(k = -1\)
容易得到 \(f[i] = max( \sum_{j = 1}^{i - 1} f[j] + k * (i - j) )\) 的转移方程。
显然,分三种情况看,
\(k = 1\) 时,\(f[i] = max(\sum_{j = 1}^{i - 1} f[j] - j + i)\),即需要找到在 \(i\) 之前最大的 \(f[j] - j\),这步操作可以通过线段树或者树状数组去快速查询和维护。
\(k = 0\) 时,\(f[i] = max(\sum_{j = 1}^{i - 1} f[j]\),即需要找到在 \(i\) 之前最大的 \(f[j]\),同样通过上述数据结构去操作。
\(k = -1\) 时,值是减少的,对于一段总和为负数的区间,因为它的子区间可能是正的,所以最优的策略肯定是继续划分,直到不能划分为止,即最后会剩下一个长为 1 的负数区间。所以这种情况就是之前最大的值 -1。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 5e5 + 10;
LL T, n;
struct fwt{
	LL a[N], n;
	LL lowbit(LL k){
		return k & -k;
	}
	void update(LL x, LL k){
		while (x <= n){
			a[x] = max(a[x], k);
			x += lowbit(x);
		}
	}
	LL query(LL x){
		LL t = -1e18;
		while (x != 0){
			t = max(t, a[x]);
			x -= lowbit(x);
		}
		return t;
	}
	void init(LL m){
		n = m;
		for (int i = 0; i <= n + 1; i ++ )
			a[i] = -1e18;
	}
}f1, f2;
void solve(){
	cin >> n;
	vector <LL> f(n + 1), t, s(n + 1);
	for (int i = 1; i <= n; i ++ ){
		cin >> s[i];
		s[i] += s[i - 1];
		t.push_back(s[i]);
	}
	t.push_back(0);
	sort(t.begin(), t.end());
	t.erase(unique(t.begin(), t.end()), t.end());
	for (int i = 0; i <= n; i ++ )
		s[i] = lower_bound(t.begin(), t.end(), s[i]) - t.begin() + 1;
	f1.init(n);
	f2.init(n);
	f1.update(s[0], 0);
	f2.update(s[0], 0);
	for (int i = 1; i <= n; i ++ ){
		f[i] = f[i - 1] - 1;
		f[i] = max( f[i], i + f1.query(s[i] - 1) );
		f[i] = max( f[i], f2.query(s[i]) );
		f1.update(s[i], f[i] - i);
		f2.update(s[i], f[i]);
	}
	cout << f[n] << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> T;
	while (T--)
		solve();
	return 0;
}
posted on 2022-04-23 18:57  Hamine  阅读(105)  评论(0编辑  收藏  举报