1122考试T2

1122考试T2

​ 题目大意:

​ 有(n)个物品需要被运走, 每个物品都有两个属性值(w,s). 现在有两种车, 第一种车有(A)辆, 可以运送(w)严格小于(x_i)的物品, 对(s)不做要求.第二种车有(B)辆可以运送(s)严格小于(y_i)的物品,对(w)不做要求.每个车子运送一个物品需要花费1的时间. 问最短多长时间可以把所有物品运送完.如果不可能运送完则输出"-1".

(n <= 1e6, A, B <= 50000).

​ 二分 + 贪心 + 优先队列.

​ 将(x_i)从小到大排序, 将(y_i)从大到小排序, 将物品按(w)为第一关键字, (s)为第二关键字从小到大排序.

​ 我们二分最短多长时间可以把所有物品运送完.也就是每个车子最多可以运送多少物品.

​ 然后我们把物品都给第一种车, 贪心策略是是(w)小的尽量给(x)小的车子, 这样可以尽可能多的放.

​ 然后会剩下一些物品, 我们把它们投到一个大根堆里, 按(s)从大到小排序, 然后把这些物品往第二种车里放.

​ 如果说(s_i >= y_i), 也就是说当前第二种车无法装下这个物品, 那么后面的车子肯定也无法装下, 因为已经按(y_i)从大到小排序了.

​ 最后在判断一下队列里是否为空, 如果说不为空, 说明当前这个二分的值小了, 无法运完所有物品, 那么就增大这个二分的值, 反之则减小这个二分的值.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 1e6 + 5, M = 5e4 + 5;
int A, B, n, ans;
int a[M], b[M];
struct bag { int w, s; } c[N];

int cmp(int a, int b) { return a > b; }

int mmp(bag a, bag b) { return a.w == b.w ? a.s < b.s : a.w < b.w; }

int check(int t) {
	priority_queue <int> q;
	int p = 1;
	for(int i = 1;i <= A; i++) {
		while(p <= n && c[p].w < a[i]) { q.push(c[p].s); p ++; }
		for(int j = 1;j <= t && !q.empty(); j++) q.pop();
	}
	while(p <= n) { q.push(c[p].s); p ++; }
	for(int i = 1;i <= B; i++) {
		for(int j = 1;j <= t && !q.empty(); j++) 
			if(q.top() >= b[i]) return 0;
			else q.pop();
	}
	return q.empty();
}

int main() {

	A = read(); B = read(); n = read();
	for(int i = 1;i <= A; i++) a[i] = read(); 
	for(int i = 1;i <= B; i++) b[i] = read();
	for(int i = 1;i <= n; i++) c[i].w = read(), c[i].s = read();
	sort(a + 1, a + A + 1); sort(b + 1, b + B + 1, cmp); sort(c + 1, c + n + 1, mmp);
	int l = 1, r = n, mid;
	while(l <= r) {
		mid = (l + r) >> 1;
		if(check(mid)) r = mid - 1, ans = mid;
		else l = mid + 1;
 	}
 	if(!check(ans)) printf("-1"); else printf("%d", ans);

	return 0;
}
原文地址:https://www.cnblogs.com/czhui666/p/14021647.html