题意:
有n个建筑,每个建筑有修复时间和截止时间,只有一个工人,建筑之间移动的时间不计,最多可以让多少个建筑在截止时间前修复好。


思路:典型的“给程序留一个后悔机会”的贪心。


贪心可以考虑下面三种种策略:
1.我最先想到的是先修复修复时间短的建筑a,但是可能它的截止时间很晚,而有一件截止时间很早的建筑b,做了a会导致不能修复b,而如果先做b不会耽误修复a,这时这个贪心不成立。
2.按照最晚开始修复的时间(截止时间减修复时间)早晚来做,可能有一件事最晚开始修复的时间很早,但是它的修复时间很长,在这之间完全可以做两件比他开始时间晚的事,这时这个贪心不成立。
3.按截止时间早的先做,但是会有一个问题,这个建筑的修复时间很长,本来可以修复后面几个建筑的时间全被它占了。
虽然上面的三种策略都不能一步到位,但是第三种方案可以给它一个后悔的机会。
1.当某个建筑不能修复时,我们就考虑是否反悔,如果之前修复的建筑中修复时间最大的比这个建筑的修复时间还长,那么替换掉之前修复时间的建筑。
2.替换掉后,因为当前的建筑比之前的建筑截止时间晚,所以也能完成,又因为当前建筑的修复时间更短,所以后面的建筑也能正常修复,不影响先前的结果还有可能多修复几个建筑。
3.要有反悔的机会就要用一个大根堆(优先队列,队首元素最大)去存每个修复了的建筑。


Code:


#include<bits/stdc++.h>
#define  js  ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
struct node{
    ll cost,end;
}q[150005];
bool cmp(node a,node b){
    return a.end<b.end;
}
int main() {
    int n; js;
    cin>>n;
    for(int i=1;i<=n;++i) cin>>q[i].cost>>q[i].end;
    sort(q+1,q+1+n,cmp);
    priority_queue<int>que;
    ll sum=0,ans=0;
    for(int i=1;i<=n;++i) {
        if(sum+q[i].cost<=q[i].end) {
            ++ans; sum+=q[i].cost;
            que.push(q[i].cost);
        }
        else if(que.top()>q[i].cost) {
            sum=sum-que.top()+q[i].cost;
            que.pop(); que.push(q[i].cost);
        }
    }
    cout<<ans<<endl;
    return 0;
}