题目描述
小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全 毁坏。
现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。
如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
输入描述:
第一行是一个整数N接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。
输出描述:
输出一个整数S,表示最多可以抢修S个建筑.
N < 150,000; T1 < T2 < maxlongint
题解
题意就是n个建筑需要修复,只能同时修一个建筑,每个建筑修复需要t1时间,且必须在t2时间前修完,否则此建筑报废 问最多能修好多少个建筑。初看题目,想到的可能是动规,但t的范围太大,无法定义状态。由于没有权值,所以我们肯定考虑选花时间小的建筑,于是我们把建筑按花的时间从小到大排序,能选就选,选了的我们让它在尽量靠后的时间修(一个经典贪心套路)。初始当前使用时间usetime=0,能修复建筑个数ans=0; 先按照截止时间从小到大排序,如果i能选(usetime+i.x<=i.y)则选(usetime+=i.x,ans++),并把耗费时间加入到大根堆中,如果不能选(usetime+i.x>i.y),则看堆顶元素与耗费时间的大小关系,判断能否减小当前时间。跟看电视那总题有点关系。
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define lowbit(x) x&(-x) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll, ll> pll; const int N = 2e5+5; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps =1e-9; const double PI=acos(-1.0); const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1}; ll qpow(ll x,ll y){ ll ans=1,t=x; while(y>0){ if(y&1)ans*=t,ans%=mod; t*=t,t%=mod; y>>=1; } return ans%mod; } pii a[N]; bool cmp(pii x,pii y){ return x.se<y.se; } void solve(){ int n;cin>>n; for(int i=1;i<=n;i++){ cin>>a[i].fi>>a[i].se; } sort(a+1,a+1+n,cmp); priority_queue<int>q; int now=0,ans=0; for(int i=1;i<=n;i++){ if(now+a[i].fi<=a[i].se)ans++,q.push(a[i].fi),now+=a[i].fi; else { int k=q.top(); if(k>a[i].fi){ q.pop(); q.push(a[i].fi); now-=(k-a[i].fi); } } } cout<<ans; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); //int t;cin>>t; //while(t--)solve(),cout<<'\n'; solve(); return 0; }