题目链接: Packing Under Range Regulations
大致题意
有n个球, 其中第i个球可以放在[l, r]位置, 每个位置只能放一个球.
问: 能否使得n个球都有位置放.
解题思路
模拟 贪心
我们考虑模拟怎么放球最优.
首先我们可以按照区间左端点去排序, 如果左端点相同, 我们肯定先放右端点最小的.
假设当前有四个球 [ 2 , 2 ] , [ 2 , 3 ] , [ 2 , 5 ] , [ 3 , 4 ] [2, 2], [2, 3], [2, 5], [3, 4] [2,2],[2,3],[2,5],[3,4], 如果我们贪心的按照排序后的顺序放, 我们发现并不是最优的情况. 因为我们可以分配2, 3, 5, 4位置方式放完全部的球.
我们考虑为什么会出现上文的情况?
原因是, 当我把第一个球放到位置2后, 实际上再放球的位置一定≥3, 相当于左区间的限制已经变为了3, 则此时我们应当把第四个球也一起考虑进来.
我们每次应当优先放所有被考虑的球中, 右端点最小的球. 可以采用小顶堆来维护.
那么对于本题, 我们可以用 p o s pos pos表示当前放球的位置. 枚举排序后的区间 [ l , r ] [l, r] [l,r], 如果此时 p o s = = l pos == l pos==l, 我们就需要考虑当前球, 则把当前球的右端点加入堆中即可. 反之表明 p o s < l pos < l pos<l, 则我们按照堆中顺序, 填充 [ p o s , l ) [pos, l) [pos,l)区间即可. 填充后再将当前球入堆.
不合法情况: 如果堆中的右端点 小于 当前放球的位置, 则无解.
代码细节: 每次把球入堆后, 记得更新放置位置 p o s = l pos = l pos=l.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
int main()
{
int t; cin >> t;
while (t--) {
int n; scanf("%d", &n);
vector<pair<int, int>> v;
rep(i, n) {
int l, r; scanf("%d %d", &l, &r);
v.push_back({ l, r });
}
sort(v.begin(), v.end());
v.push_back({ 0x3f3f3f3f, 0x3f3f3f3f }); //处理最后的球
priority_queue<int, vector<int>, greater<>> heap; //保存所有的右端点
bool flag = 1;
int pos = -1;
for (auto& [l, r] : v) {
if (pos == l) heap.push(r);
else {
while (pos < l and !heap.empty()) {
auto op = heap.top(); heap.pop();
if (op >= pos) pos++;
else {
flag = 0;
goto here;
}
}
pos = l;
heap.push(r);
}
}
here: puts(flag ? "Yes" : "No");
}
return 0;
}