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;
}