Description
小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有(N)个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
Input
第一行是一个整数(N)接下来(N)行每行两个整数(T1),(T2)描述一个建筑:修理这个建筑需要(T1)秒,如果在(T2)秒之内还没有修理完成,这个建筑就报废了。
Output
输出一个整数S,表示最多可以抢修S个建筑.(N < 150000); (T1 < T2 < maxlongint)
Sample Input
4
100 200
200 1300
1000 1250
2000 3200
Sample Output
3
Solution
此题显然是贪心。先按(t2)排序,然后依次处理,我们维护一个大根堆, 每修理一栋建筑,我们就把这栋建筑的(t1)值加入堆,若当前无法修理 我们判断堆顶是否比这栋建筑的(t1)大,如果大,取消修理堆顶,改为修理当前建筑。这个贪心的正确性是容易证明的。处理到一个建筑时,前面的处理顺序对当前决策并无影响,所以选择放弃之前修理过的(t1)最大的必然比次大的优,因为这样虽然不能更新答案,但是可以为后面的建筑提供更多的“空间”。这样想通了代码两分钟就写好了。
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, flag = 1; char ch = getchar();
while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }
while (ch <= '9' && ch >= '0') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * flag;
}
#define N 150001
#define rep(ii, aa, bb) for (int ii = aa; ii <= bb; ii++)
#define ll long long
int n;
struct node { ll t1, t2; }a[N];
bool cmp(const node x, const node b) { return x.t2 < b.t2; }
priority_queue<ll> q;
int main() {
n = read();
rep(i, 1, n) a[i].t1 = read(), a[i].t2 = read();
sort(a + 1, a + 1 + n, cmp);
ll used = 0;
int ans = 0;
rep(i, 1, n)
if (used + a[i].t1 <= a[i].t2) ans++, used += a[i].t1, q.push(a[i].t1);
else if (q.size() && q.top() > a[i].t1) used += a[i].t1 - q.top(), q.pop(), q.push(a[i].t1);
cout << ans;
return 0;
}