P4053 [JSOI2007]建筑抢修

题目描述

小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。

输入输出格式

输入格式:

第一行是一个整数N,接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。

输出格式:

输出一个整数S,表示最多可以抢修S个建筑.

输入输出样例

输入样例#1: 
4
100 200
200 1300
1000 1250
2000 3200
输出样例#1: 
3

说明

N < 150,000; T1 < T2 < maxlongint

Solution:

  本题很显然贪心。

  开始时我按修的时间从小到大排序,然后能修就修,不能就和上一个答案比较一下能不能使总时间变得更短且满足当前这一个的时间限制。

  果然,第一遍思路总是错的$WA$了$6$个点。

  然后,想到修建所需时间没有什么用,先修后修都无所谓关键是不超过限制时间,所以总时间越短,更利于满足限制条件,于是应该是按限制时间从小到大排序。

  那么,排序后还是能修就修,否则就和前面修过的所有建筑中时间最大的比较一下,看能否替换使总时间变小且满足当前这个的时间限制,替换后虽然不会使得答案变大,但能让总时间减小,使后面选择时满足时间限制的几率变大。那么所有修过的建筑所需时间用一个大根堆维护一下,就$OK$了。

代码:

#include<bits/stdc++.h>
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=150005;
int n,ans,all;
struct node{
    int t,ct;
    bool operator<(const node a)const{return ct==a.ct?t<a.t:ct<a.ct;}
}a[N];
priority_queue<int>q;
inline int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9')x=getchar();
    while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar();
    return a;
}
int main(){
    n=gi();
    For(i,1,n)a[i].t=gi(),a[i].ct=gi();
    sort(a+1,a+n+1);
    For(i,1,n){
        if(all+a[i].t<=a[i].ct){
            ans++;all+=a[i].t;
            q.push(a[i].t);
        }
        else {
            int p=q.top();
            if(a[i].t<p&&all-p+a[i].t<=a[i].ct){
                q.pop();q.push(a[i].t);
                all=all-p+a[i].t;
            }
        }
    }
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/five20/p/9041679.html