P5896 [IOI2016] aliens (斜率优化 dp+wqs 二分)

我们可以把所有点都对称到主对角线下方。

然后每个点如果想被覆盖都会有一个最小的三角形,我们可以贪心的只留必须选的点。如果把剩下的点按 \(x\) 坐标升序排序,可以发现他们的 \(y\) 坐标也是升序排序的。

记剩余点个数为 \(n\),显然每个点都选自己的最小三角形最好。但是有可能 \(n>K\),即我们不得不合并一些连续的最小三角形。

可以 dp,\(f_{i,k}\) 表示覆盖前 \(i\) 个点,用了 \(k\) 个三角形的最少覆盖点。

枚举 \(j\),把 \(j+1\sim i\) 用一个三角形覆盖,转移即可。

\[f_{i,k}={f_{j,k−1}+(x_i−y_j+1+1)}^2 \]

注意处理重叠的点,要减去这些点,可以直接记在 \(f_{j,k-1}\) 里。

发现可以斜率优化,\(O(n\times k)\)

还是过不去,我们考虑 wqs 二分,降维打击!

复杂度 \(O(n\log m)\)

#include <bits/stdc++.h>
using namespace std;
#define N 100010
#define ll long long
#define inf 0x3f3f3f3f
struct P {
	int x, y;
} p[N];
inline bool cmp(P a, P b) {
	return a.x == b.x ? a.y > b.y : a.x < b.x;
}
inline ll sqr(ll x) {
	return x * x;
}
ll f[N];
int cnt[N], q[N], qh, qt;
inline double slope(int k1, int k2) {
	return (f[k2] - f[k1] + sqr(p[k2 + 1].y) - sqr(p[k1 + 1].y)) * 1.0 / (2 * (p[k2 + 1].y - p[k1 + 1].y));
}
inline int solve(int n, ll C) {
	qh = 1;
	qt = 0;
	q[++qt] = 0;
	for (int i = 1; i <= n; ++i) {
		while (qh < qt && slope(q[qh], q[qh + 1]) < p[i].x + 1) ++qh;
		f[i] = f[q[qh]] + sqr(p[i].x - p[q[qh] + 1].y + 1) + C, cnt[i] = cnt[q[qh]] + 1;
		if (i == n) break;
		if (p[i + 1].y <= p[i].x) f[i] -= sqr(p[i].x - p[i + 1].y + 1);
		while (qh < qt && slope(q[qt - 1], q[qt]) > slope(q[qt], i)) --qt;
		q[++qt] = i;
	}
	return cnt[n];
}
long long take_photos(int n, int m, int k, std::vector<int> r, std::vector<int> c) {
	ll ans = 0, l = 0, rr = (ll)m * m + 10;
	for (int i = 0; i < n; ++i) {
		if (r[i] < c[i]) p[i + 1].x = c[i], p[i + 1].y = r[i];
		else p[i + 1].x = r[i], p[i + 1].y = c[i];
	}
	sort(p + 1, p + n + 1, cmp);
	m = 0;
	p[0].y = -1;
	for (int i = 1; i <= n; ++i) {
		while (m && p[m].y >= p[i].y) --m;
		p[++m] = p[i];
	}
	n = m;
	for (int i = 1; i <= n; ++i) {
		ans += sqr(p[i].x - p[i].y + 1);
		if (i < n && p[i + 1].y <= p[i].x) ans -= sqr(p[i].x - p[i + 1].y + 1);
	}
	if (n <= k) return ans;
	while (l <= rr) {
		ll mid = l + rr >> 1;
		int res = solve(n, mid);
		if (res <= k) rr = mid - 1, ans = f[n];
		else l = mid + 1;
	}
	rr++;
	ans -= rr * k;
	return ans;
}
posted @ 2024-04-29 10:00  BadBadBad__AK  阅读(21)  评论(0编辑  收藏  举报