【BZOJ3675】【APIO2014】序列分割

【题目链接】

【思路要点】

  • 凸优化 + 决策单调性优化 d p dp dp
  • 时间复杂度 O ( N L o g V L o g N ) O(NLogVLogN) O(NLogVLogN)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct info {ll cost; int cnt; };
info operator + (info a, ll b) {return (info) {a.cost + b, a.cnt + 1}; }
bool operator < (info a, info b) {
	if (a.cost == b.cost) return a.cnt < b.cnt;
	else return a.cost < b.cost;
}
bool operator <= (info a, info b) {
	if (a.cost == b.cost) return a.cnt <= b.cnt;
	else return a.cost < b.cost;
}
bool operator > (info a, info b) {
	if (a.cost == b.cost) return a.cnt > b.cnt;
	else return a.cost < b.cost;
}
bool operator >= (info a, info b) {
	if (a.cost == b.cost) return a.cnt >= b.cnt;
	else return a.cost < b.cost;
}
info Max[MAXN], Min[MAXN];
int n, k, a[MAXN]; ll Extra, s[MAXN];
ll cost(int l, int r) {return (s[r] - s[l]) * (s[r] - s[l]); }
info TransMax(int x, int y) {return Max[x] + (cost(x, y) + Extra); }
info TransMin(int x, int y) {return Min[x] + (cost(x, y) + Extra); }
void check(ll extra) {
	int LMax = 1, RMax = 1, LMin = 1, RMin = 1; Extra = extra;
	static pair <int, pair <int, int> > SMax[MAXN], SMin[MAXN];
	SMax[1] = make_pair(0, make_pair(1, n));
	SMin[1] = make_pair(0, make_pair(1, n));
	for (int i = 1; i <= n; i++) {
		Max[i] = TransMax(SMax[LMax].first, i);
		Min[i] = TransMin(SMin[LMin].first, i);
		if (++SMax[LMax].second.first > SMax[LMax].second.second) LMax++;
		if (++SMin[LMin].second.first > SMin[LMin].second.second) LMin++;
		while (LMax <= RMax && TransMax(i, SMax[RMax].second.first) >= TransMax(SMax[RMax].first, SMax[RMax].second.first)) RMax--;
		if (LMax > RMax) SMax[++RMax] = make_pair(i, make_pair(i + 1, n));
		else if (TransMax(i, n) > TransMax(SMax[RMax].first, n)) {
			int l = SMax[RMax].second.first, r = SMax[RMax].second.second + 1;
			while (l < r) {
				int mid = (l + r) / 2;
				if (TransMax(i, mid) > TransMax(SMax[RMax].first, mid)) r = mid;
				else l = mid + 1;
			}
			SMax[RMax].second.second = l - 1;
			SMax[++RMax] = make_pair(i, make_pair(l, n));
		}
		while (LMin <= RMin && TransMin(i, SMin[RMin].second.first) <= TransMin(SMin[RMin].first, SMin[RMin].second.first)) RMin--;
		if (LMin > RMin) SMin[++RMin] = make_pair(i, make_pair(i + 1, n));
		else if (TransMin(i, n) < TransMin(SMin[RMin].first, n)) {
			int l = SMin[RMin].second.first, r = SMin[RMin].second.second + 1;
			while (l < r) {
				int mid = (l + r) / 2;
				if (TransMin(i, mid) < TransMin(SMin[RMin].first, mid)) r = mid;
				else l = mid + 1;
			}
			SMin[RMin].second.second = l - 1;
			SMin[++RMin] = make_pair(i, make_pair(l, n));
		}
	}
}
int main() {
	read(n), read(k), k++;
	for (int i = 1; i <= n; i++)
		read(a[i]), s[i] = s[i - 1] + a[i];
	ll l = 0, r = 1e18;
	while (true) {
		ll mid = (l + r) / 2; check(mid);
		if (Min[n].cnt <= k && Max[n].cnt >= k) {
			printf("%lld\n", (s[n] * s[n] - Min[n].cost + mid * k) / 2);
			return 0;
		}
		if (Min[n].cnt < k) r = mid - 1;
		else l = mid + 1;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值