bzoj1029 [JSOI2007]建筑抢修

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;
}
posted @ 2018-02-05 09:26  aziint  阅读(140)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.