漩涡般的阴谋
Description
机房一条街有n个机房,第i个机房的坐标为xi,小X的家坐标为0。小X在街上移动的速度为1,即从x1到x2所耗费的时间为|x1 - x2|。
每个机房的学生数量不同,ACM题目水平也良莠不齐,小X到达第i个机房后,可以花ti时间想题然后瞬时AK:当然,也可以过机房而不入。
小X现在只有m个单位时间,之后他就该赶首去打codeforces了。现在他想知道自己最多能在多少个机房AK,希望你帮帮他。
Analsis
如果已确定了到达机房的最大深度,那么是不是可以用贪心解决呢?很显然是的,只要优先打耗时短的题目自然就可以AK最多的机房。
对于深度的选择,可能会想到二分?但是研究一下可以发现,机房的深度问题不具有有序性,即靠后的机房也可能有耗时短使结果更优的,那么只能朴素枚举1~n。深度选择无法优化、为了过掉这题,要把贪心操作限制在O(logn)以内。找冗余计算可以发现对于前i个机房而言,前i-1个机房反复处理太多次,真正需要更新处理的只有第i个。判断第i个是否会影响对机房的选择,只要将其与以选入的机房堆比较,如果多做一个不会超过时间,自然直接AK掉;如果超时了那就与已选的最耗时的比较,更优就替换,不如就不管。堆处理的操作刚好是O(logn),这题就过掉了。
Code
#include <bits/stdc++.h>
#define ll long long
int n,sum,ans;
ll m,cnt;
std::pair<ll,ll> r[100010];
bool flag;
std::priority_queue <ll> room;
void treat(ll x,ll t){
while(!room.empty()&&cnt+x>m){
cnt-=room.top();
sum--;
room.pop();
}
if(cnt+x>m){
flag=true;
return;
}
if(cnt+x+t<=m){
cnt+=t;
sum++;
room.push(t);
}
else if(!room.empty()&&t<room.top()){
cnt-=room.top()-t;
room.pop();
room.push(t);
}
ans=std::max(ans,sum);
}
int main(){
freopen("plan.in","r",stdin);
freopen("plan.out","w",stdout);
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&r[i].first,&r[i].second);
std::sort(r+1,r+n+1);
for(int i=1;i<=n&&!flag;i++)
treat(r[i].first,r[i].second);
printf("%lld\n",ans);
return 0;
}