可反悔的贪心。从小到大对倒塌时长排序,先修快倒塌的(从小到大枚举修理时长)。如果时间不够修当前的楼,就先判断这个楼是否有必要修(修它的用时<修之前楼用时的最大值,就有必要修)。如果没必要就不修,如果有必要就把前面修的时间最长的楼去掉,不去修它。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
priority_queue<ll> q;//大根堆
struct build{
ll t1;
ll t2;
}a[150010];
ll n;
int comp(struct build x,struct build y){//按照倒塌时长从小到大排序
return x.t2<y.t2;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin >> n;
for(int i=0;i<n;i++)
cin >> a[i].t1 >> a[i].t2;
sort(a,a+n,comp);
ll pt=0;//已经过去的时间pass time
ll saved=0;//已经修好的楼
ll maxsaved=0;//最多能修好的楼
for(int i=0;i<n;i++){
if(pt+a[i].t1<a[i].t2){//能修好
q.push(a[i].t1);
pt+=a[i].t1;
saved++;
maxsaved=max(maxsaved,saved);
}
else{//时间不够,修不好
if(a[i].t1<q.top()){//当前的楼用时不是最多,有必要修当前的楼
while(pt+a[i].t1>a[i].t2){//把前面时间长的扔了,修当前这个
ll x = q.top();
q.pop();
pt-=x;
saved--;
}
q.push(a[i].t1);
pt+=a[i].t1;
saved++;
maxsaved=max(maxsaved,saved);
}
}
}
cout << maxsaved << "\n";
return 0;
}---------------------一个优化--------------------------
先假设当前这个楼能修,直接放进堆里。如果发现这个楼需要修(修这个楼用时<大根堆的堆顶),就从这个堆中把修理用时长的楼删去
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
priority_queue<ll> q;//大根堆
struct build{
ll t1;
ll t2;
}a[150010];
ll n;
int comp(struct build x,struct build y){//按照倒塌时长从小到大排序
return x.t2<y.t2;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin >> n;
for(int i=0;i<n;i++)
cin >> a[i].t1 >> a[i].t2;
sort(a,a+n,comp);
ll pt=0;//已经过去的时间pass time
ll saved=0;//已经修好的楼
ll maxsaved=0;//最多能修好的楼
for(int i=0;i<n;i++){
//先假设能修
q.push(a[i].t1);
pt+=a[i].t1;
saved++;
while(a[i].t1<=q.top() && pt>a[i].t2){//当前的楼要修,且时间不够,就删去其他用时长的楼
ll x = q.top();
q.pop();
pt-=x;
saved--;
}
maxsaved=max(maxsaved,saved);
}
cout << maxsaved << "\n";
return 0;
}
京公网安备 11010502036488号