漩涡般的阴谋

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;
}

猜你喜欢

转载自www.cnblogs.com/qswx/p/9492548.html