【题解】【LuoguP5894】【IOI2013】robots
题目链接
题目解法
题目等价于一些点在平面上,一个机器人可以取走做平面或下平面的所有点,一轮一个机器人只能取一次。求最少多少次才能把所有点都取走。
先二分多少次可以把所有点都去走。那么每个机器人取的次数 (le m) 。考虑贪心。将所有点用 (x) 轴排序,从可取得范围小到可取得范围大考虑所有可以取左平面的机器人。对于每个机器人,很明显先取(y) 坐标大得机器人。再考虑所有取下平面得机器人即可。
那么需要做以下几件事情:
- 首先判断是否无解。
- 将所有左平面机器人、右平面机器人按照可取范围大小从小到大排序。
- 将所有点按照 (x) 轴排序。
- 二分取的次数 (m) 。
- 从小到大枚举所有取左平面的机器人,对于当前机器人 (a_i) ,把所有 (a_i) 可取的点按照 (y) 轴的顺序插入到一个堆里。取最靠上的 (m) 个点。
- 剩下一大堆取下平面的机器人。从可以取的部分少的机器人到多的机器人,每次取最靠下并且可取的 (m) 个机器人即可。
总结
- 本来以为二分并没有意义。但实际上二分有意义的。因为机器人的操作交换也没有问题,所以二分一个数 (m) 的意义就是可以将一个机器人的所有操作一起做了,而不用做一个操作换一个机器人。
代码
这次注意开 long long 了。
#include <cstdio>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int CT = 1e6 + 5, CAB = 5e4 + 5;
int a, b, t, X[CAB], Y[CAB];
struct Toy {
int w, s;
Toy(int _w = 0, int _s = 0) : w(_w), s(_s) {}
} toy[CT];
bool cmp(const Toy &x, const Toy &y) { return x.w < y.w; }
struct cmp1 {
bool operator()(const Toy &x, const Toy &y) { return x.s < y.s; }
//如果函数返回值是 1,那么 y在上面
};
priority_queue<Toy, vector<Toy>, cmp1> H1;
int que[CT];
bool check(int ans) {
while (!H1.empty()) H1.pop();
int pt = 1;
for (int i = 1; i <= a; ++i) {
while (pt <= t && toy[pt].w < X[i]) {
H1.push(toy[pt]);
++pt;
}
for (int j = 1; j <= ans; ++j) {
if (H1.empty()) break ; //这个地方开始写成了 !H1.empty()
H1.pop();
}
}
//还可能有一些根本没有被塞进去的点(就是没有一个x[i]的机器人能消灭他),这里得加上
for (int i = pt; i <= t; ++i)
H1.push(toy[i]);
int tail = 0;
while (!H1.empty()) {
que[++tail] = H1.top().s;
H1.pop();
}
sort(que + 1, que + tail + 1);
pt = 1;
for (int i = 1; i <= b; ++i) {
int cnt = 0;
while (pt <= tail && que[pt] < Y[i] && cnt < ans) {
++cnt;
++pt;
}
}
if (pt == tail + 1) return 1;
else return 0;
}
int main() {
scanf("%d%d%d", &a, &b, &t);
for (int i = 1; i <= a; ++i) scanf("%d", &X[i]);
for (int i = 1; i <= b; ++i) scanf("%d", &Y[i]);
sort(X + 1, X + a + 1);
sort(Y + 1, Y + b + 1);
for (int i = 1; i <= t; ++i) {
scanf("%d%d", &toy[i].w, &toy[i].s);
if (X[a] <= toy[i].w && Y[b] <= toy[i].s) {
printf("-1
");
return 0;
}
}
sort(toy + 1, toy + t + 1, cmp);
int L = 1, R = 1e6, ans;
while (L <= R) {
int mid = (L + R) >> 1;
if (check(mid)) {
ans = mid;
R = mid - 1;
} else
L = mid + 1;
}
printf("%d
", ans);
return 0;
}