AT2645 [ARC076D] Exhausted?题解
题目描述
有 \(m\) 个椅子在数轴上排列,第 \(i\) 张椅子的坐标为 \(i\)。
高桥君和他的朋友一共有 \(n\) 个人。高桥君他们因为玩了太久的游戏,大家的腰和背都很痛,所以他们很有必要坐在椅子上休息一下。
高桥君他们每个人坐的椅子的坐标都很讲究,第 \(i\) 个人想坐在坐标不大于 \(l_i\) 的椅子上,或者坐在坐标不小于 \(r_i\) 的椅子上。当然,一个的椅子只能坐一个人。
可这样计算下去,可能会让他们不能都坐在椅子上休息。青木君关心高桥君他们的健康,尽可能多地增加椅子,让高桥君他们都能够坐在椅子上休息。 椅子可以添加到任意的实数坐标上,请求出需要添加椅子数量的最小值。
输入格式
第一行输入两个数 \(n\) 和 \(m\)。
接下来的第二行到 \(n+1\) 行依次输入 \(l_i\) 和 \(r_i\)。
输出格式
输出需要添加的椅子数量的最小值。
样例一
input
7 6
0 7
1 5
3 6
2 7
1 6
2 6
3 7
output
2
样例解释
\(4\) 个人依次坐在坐标为 \(3,2,1,4\) 的椅子上,所以椅子不需要添加。
样例二
input
3 1
1 2
1 2
1 2
output
2
样例解释
如果将椅子添加到坐标 \(0\) 和 \(7\),则可以将 \(7\) 人按顺序放在坐标 \(0,5,3,2,6,1,7\) 中。
做法
本题有 hall 定理做法,详见大佬的博客,这里主要讲解贪心。
思路:让所有的人先尽可能坐在左面,坐不下的做右面,然后实在坐不了的就填椅子。
实现:
- \(ex_i\) 数组:果为 -1 即表示 \(i\) 这个位置的椅子是空的,0 表示坐了人,其余数字均表示有 \(ex_i\) 个人还没有坐在椅子上,他们不可以坐在坐标小于 \(i\) 的椅子上。
- 把所有人按照以 \(l\) 为第一关键字,\(r\) 为第二关键字排序,\(ex\) 数组初值均为 -1,每次选择一个人,看他前面能坐的椅子是否坐满,如果没满,就直接做当前所剩椅子中最左面的一个,并插入到优先队列中表示可以被替换,如果已经满了,就要从所有可以被替换的这些人里找第二关键字最小的一个替换(这样可以给后面留足够大的空间让更多人坐),这样的话自己就坐在了。
- 统计答案:考虑 \(ex_i\) 数组后缀和的含义即为从 \(i\) 到 \(n\) 有多少个人没有椅子,且这些人一定要坐在坐标大于等于 \(i\) 的位置,这样后缀和中最大的即为答案。
思路来自大佬 @tjn1234
代码
#include <bits/stdc++.h>
using namespace std;
namespace Std {
int n, m, now, ex[200010], ans, res;
struct node {
int l, r;
friend bool operator<(const node& a, const node& b) {
return (a.l == b.l) ? a.r < b.r : a.l < b.l;
}
} t[200010];
struct num {
int sum;
friend bool operator<(const num& a, const num& b) { return a.sum > b.sum; }
};
priority_queue<num> q;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &t[i].l, &t[i].r);
}
sort(t + 1, t + n + 1);
for (int i = 1; i <= m; i++) ex[i] = -1;
for (int i = 1; i <= n; i++) {
if (t[i].l == 0) {
ex[t[i].r]++;
} else if (t[i].l == now) {
num u = q.top();
q.pop();
ex[u.sum]++;
u.sum = t[i].r;
q.push(u);
} else {
ex[++now]++;
num u;
u.sum = t[i].r;
q.push(u);
}
}
for (int i = m + 1; i >= 0; i--) {
res += ex[i];
ans = max(ans, res);
}
printf("%d\n", ans);
return 0;
}
} // namespace Std
int main() { return Std::main(); }
未经授权,禁止转载。