题解:P11512 [ROIR 2017 Day 2] 力场
以下两种思路不可行:
- 二分答案验证:需要判断给定的面积下限(二分中点)是否可以实现。由于无法确定每一个满足面积要求的矩形是否选取,不存在
O(n) 的方案。总复杂度不能做到O(n\log n) 。 - 三分法寻找最大值:假设当一个矩形的
x 长度满足x \geq x_\mathrm m 时,我们将其选入候选集中。如果候选集的元素数目大于等于k ,则选中第k 大的y_k 坐标,计算x_\mathrm my_k ,得到约束x \geq x_\mathrm m 下的最大公共面积S(x_\mathrm m) ;否则定义S(x_\mathrm m) = 0 。函数S(x_\mathrm m) 是上凸函数,对其进行优化可以得到全局最优解。但其变化率可能在多处为 0,这导致三分法十分不便。
以上第二种不可行思路与本题的一种常规解法已经十分接近。可以在对矩形右上角坐标点
以上过程存在选取的
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
cin.tie(0)->sync_with_stdio(0);
int n, k;
cin >> n >> k;
vector<pair<int, int>> p(n); // 每个矩形右上角的点
for(auto &xy : p) cin >> xy.first >> xy.second;
sort(p.begin(), p.end()); // 按照先 x 后 y 的优先级排序
long ans = 0; // 最大公共面积
priority_queue<int, vector<int>, greater<int>> pq; // 大小不超过 k 的小顶堆
for(int i = p.size() - 1; i >= 0; --i) { // 计算/维护当前 x 下限要求的 y 的第 k 大值
auto [x, y] = p[i]; // 横坐标下降至 x,纵坐标新增 y
if((int)pq.size() == k) { // 堆满
if(pq.top() < y) pq.pop(), pq.push(y); // 选择性置换
} else { // 堆不满
pq.push(y); // 插入 y
}
if((int)pq.size() == k) { // 堆顶成为了序列流第 k 大
ans = max(ans, (long)x * pq.top()); // 计算面积
}
}
cout << ans << endl;
return 0;
}