主页
最近更新
P5896 [IOI2016] aliens (斜率优化 dp+wqs 二分)
最后更新于 2025-05-01 22:33:48
作者
PokerKing
分类
题解
题解
P5896
复制 Markdown
更新文章内容
我们可以把所有点都对称到主对角线下方。 然后每个点如果想被覆盖都会有一个最小的三角形,我们可以贪心的只留必须选的点。如果把剩下的点按 $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)$。 ```cpp #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; } ```
Loading...
点赞
0
收藏
0