P4053 [JSOI2007] 建筑抢修
[JSOI2007] 建筑抢修
题目描述
小刚在玩 JSOI 提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T 部落消灭了所有 Z 部落的入侵者。但是 T 部落的基地里已经有 \(N\) 个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T 部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
输入格式
第一行,一个整数 \(N\)。
接下来 \(N\) 行,每行两个整数 \(T_1,T_2\) 描述一个建筑:修理这个建筑需要 \(T_1\) 秒,如果在 \(T_2\) 秒之内还没有修理完成,这个建筑就报废了。
输出格式
输出一个整数 \(S\),表示最多可以抢修 \(S\) 个建筑。
样例 #1
样例输入 #1
4
100 200
200 1300
1000 1250
2000 3200
样例输出 #1
3
提示
对于 \(100 \%\) 的数据,\(1 \le N < 150000\),\(1 \le T_1 < T_2 < 2^{31}\)。
解析
将截止时间按升序排序,记录一个变量now表示当前一共花的时间,枚举每个建筑,如果now加上当前建筑所需时间不超过他的截止时间,那么答案加一,将他的时间花费加入大根堆;大于截止时间的话,判断一下当前建筑的花费是否小于堆顶,小于则删去堆顶将其入堆(因为该建筑的花费小,且截止时间又不小于堆顶,选择修建他肯定更优),基于贪心思路,使得now尽量小,这样后面的建筑更有机会被修建。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 150010;
struct node {
int x, y;
}a[N];
bool cmp(node a, node b) {
return a.y < b.y;
}
priority_queue<int> q;
signed main() {
int n;
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i].x >> a[i].y;
sort(a + 1, a + n + 1, cmp);
int now = 0, ans = 0;
for (int i = 1; i <= n; i ++) {
if (now + a[i].x <= a[i].y) {
ans ++;
now += a[i].x;
q.push(a[i].x);
}
else if (a[i].x < q.top()) {
now = now - q.top() + a[i].x;
q.pop(), q.push(a[i].x);
}
}
cout << ans << '\n';
}