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';
}

image

posted @ 2022-10-14 14:24  YHXo  阅读(18)  评论(0编辑  收藏  举报