AtCoder Beginner Contest 215F题
作者:
白墙
,
2021-08-23 15:54:48
,
所有人可见
,
阅读 335
F - Dist Max 2
https://atcoder.jp/contests/abc215/tasks/abc215_f
大概题意就是找两个点的坐标差的最小值的最大值。这就提示我们可以用二分来做。于是我们需要想办法将问题变成判定问题
条件:min(abs(x[i] - x[j]), abs(y[i] - y[j])) >= k。将这个条件转化为一个等价的形式。
abs(x[i] - x[j]) >= k 并且abs(y[i] - y[j]) >= k。等价与对于一个点(x, y),对于其他的点(x[i], y[j])并且这个点满足性质x[i] - x >= k,是否能够找到最大或者最小的纵坐标abs(y[i] - y) >= k的点。如果能够找到那么这个k就是合法的。
我们需要找到一个最大的k,所以是找合法区间的右边界
于是我们可以考虑维护一个队列。先按照横坐标从小到大排序
对于这个队列满足的性质 队首元素为a, 对于给定的点(x, y)
a.first -x >= k.但是纵坐标不一定满足满足。因此我们需要在满足这个性质的队列中找到一个最大或者最小的纵坐标。然后判断是否满足性质abs(minv - y) >= k 或者 abs(maxv - y) >= k
代码如下
#include <iostream>
#include <queue>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int>PII;
const int N = 1e5 + 10;
vector<PII> v;
int n;
int main () {
cin >> n;
for (int i = 0; i < n; i ++) {
int x, y;
cin >>x >>y;
v.push_back({x, y});
}
sort (v.begin(), v.end());
int l = 0, r = 1e9;
while (l < r) {
int mid = l + r + 1 >> 1;
int minv = 1e9, maxv = 0;
queue<PII> q;
bool able = false;
for (auto &t: v) {
while(q.size()) {
if (q.front().first > t.first - mid) break;
maxv = max (maxv, q.front().second);
minv = min (minv, q.front().second);
q.pop();
}
if (t.second - minv >= mid || maxv - t.second >= mid) able = true;
q.push(t);
}
if (able) l = mid;
else r = mid - 1;
}
cout << l <<endl;
return 0;
}
聚聚加油!
聚聚一起加油!