[BZOJ]1029: [JSOI2007]建筑抢修

https://www.lydsy.com/JudgeOnline/problem.php?id=1029

题意:给出n个建筑的自爆时间和修复时间,求最多在自爆时间前能修复多少建筑。

 

一开始的naive想法:这不按自爆时间排个序,第二关键字为修复时间,升序就行?

但是这样是可以举出反例的,比如存在一个建筑,自爆时间略大于前一个,但是修复时间短,而前一个修复时间长,这两个只能选一个修,显然应该选后面那个修复时间短的,虽然不会增加答案,但是会减少时间

 

所以在对y升序排序的基础上,用一个大根堆维护之前出现的最大修复时间,在无法修复时,考虑把前面最大的替换掉(仅在当前建筑修复时间<最大修复时间时)。

 

贪心的后悔策略

 

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=150005;

int n;
struct Node{
    int x,y;
}a[MAXN];
bool cmp(const Node &l,const Node &r){
    return l.y==r.y?l.x<r.x:l.y<r.y;
}

priority_queue<unsigned long long> Q;

int main(){
    n=rd();
    for(int i=1;i<=n;i++){
        a[i].x=rd();a[i].y=rd();
    }
    sort(a+1,a+1+n,cmp);
    long long cur=0;
    unsigned long long cnt=0;
    for(int i=1;i<=n;i++){
        if(cur+a[i].x>a[i].y) {
            if(a[i].x<Q.top()){
                cur+=(a[i].x-Q.top());
                Q.pop();Q.push(a[i].x);
            }
            continue;
        }
        cnt++;
        cur+=a[i].x;
        Q.push(a[i].x);
    }
    cout<<cnt<<endl;
    return 0;
}

 

posted @ 2018-07-25 10:13  GhostCai  阅读(93)  评论(0编辑  收藏  举报