Acwing163 生日礼物(WQS 二分)

原题链接:https://www.acwing.com/problem/content/description/165/
这题我的第一反应就是 WQS 二分,发现题解没有类似的想法,于是记录一下。
首先,考虑确定分为 \(m\) 段怎么做,我们可以设 \(f[n][m][0/1]\) 表示前 \(n\) 个数,分为 \(m\) 段,当前这个数取不取,最大的子段和。
那么显然有转移式:

\[f[n][m][0] = \max \{f[n-1][m][1], f[n-1][m][0]\}\\ f[n][m][1] = \max \begin{cases} f[n-1][m][1] + a[n]\\ f[n-1][m-1][0] + a[n]\\ f[n-1][m-1][1] + a[n] \end{cases} \]

容易分析该 \(dp\) 具有上凸性,即 \(\max \{f[n][m][0], f[n][m][1]\}\) 关于 \(m\) 是个上凸函数。于是如果给定一个 \(m\),我们能够通过 WQS 二分(枚举斜率去切这个凸包)来求出答案。
可是,本题要求的是不大于 \(m\) 的最优情况,同样利用 \(dp\) 的上凸性,我们可以三分搜索这个 \(m\),再套上 WQS 二分,即可求得答案。
时间复杂度 \(O(n\log m \log \sum |A_i|)\)
这个时间复杂度还是比较高的,在 Acwing 上提交需要套上八聚氧才能通过(放在博客上就不加八聚氧了,太丑了)

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;
typedef long long ll;
int n, m;
int a[maxn];
ll f[maxn][2], g[maxn][2];

pair<ll, ll> dp(ll k) {
	f[0][1] = -2e9;
	for (int i = 1; i <= n; i++) {
		int mx = max(f[i - 1][0], f[i - 1][1]); f[i][0] = mx;
		if (f[i - 1][0] == mx) g[i][0] = g[i - 1][0];
		else g[i][0] = g[i - 1][1];
		mx = max(f[i - 1][1] + a[i], max(f[i - 1][0] + a[i] - k, f[i - 1][1] + a[i] - k)); f[i][1] = mx;
		if (f[i - 1][0] + a[i] - k == mx) g[i][1] = g[i - 1][0] + 1;
		else if (f[i - 1][1] + a[i] - k == mx) g[i][1] = g[i - 1][1] + 1;
		else g[i][1] = g[i - 1][1];
	}
	if (f[n][1] >= f[n][0]) return make_pair(f[n][1], g[n][1]);
	else return make_pair(f[n][0], g[n][0]);
}

ll solve(ll x) {
	ll lb = -1e9, rb = 1e9;
	while (lb < rb) {
		int mid = (lb + rb) >> 1; pair<ll, ll> tmp = dp(mid);
		if (tmp.second > x) lb = mid + 1;
		else if (tmp.second == x) { lb = mid; break; }
		else rb = mid;
	}
	return dp(lb).first + x * lb;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int lb = 0, rb = m;
	while (rb - lb > 2) {
		int lmid = lb + (rb - lb) / 3, rmid = rb - (rb - lb) / 3;
		if (solve(lmid) > solve(rmid)) rb = rmid;
		else lb = lmid;
	}
	ll ans = 0;
	for (int i = lb; i <= rb; i++) ans = max(ans, solve(i));
	printf("%lld\n", ans);
	return 0;
}
posted @ 2022-04-09 11:12  alfayoung  阅读(36)  评论(0编辑  收藏  举报