【题解】【LuoguP5894】【IOI2013】robots

【题解】【LuoguP5894】【IOI2013】robots

题目链接

点击打开链接

题目解法

题目等价于一些点在平面上,一个机器人可以取走做平面或下平面的所有点,一轮一个机器人只能取一次。求最少多少次才能把所有点都取走。

先二分多少次可以把所有点都去走。那么每个机器人取的次数 (le m) 。考虑贪心。将所有点用 (x) 轴排序,从可取得范围小到可取得范围大考虑所有可以取左平面的机器人。对于每个机器人,很明显先取(y) 坐标大得机器人。再考虑所有取下平面得机器人即可。

那么需要做以下几件事情:

  1. 首先判断是否无解。
  2. 将所有左平面机器人、右平面机器人按照可取范围大小从小到大排序。
  3. 将所有点按照 (x) 轴排序。
  4. 二分取的次数 (m)
  5. 从小到大枚举所有取左平面的机器人,对于当前机器人 (a_i) ,把所有 (a_i) 可取的点按照 (y) 轴的顺序插入到一个堆里。取最靠上的 (m) 个点。
  6. 剩下一大堆取下平面的机器人。从可以取的部分少的机器人到多的机器人,每次取最靠下并且可取的 (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;
}
原文地址:https://www.cnblogs.com/YouthRhythms/p/13363830.html