漩涡般的阴谋

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;
}
posted @ 2018-08-17 11:46  Srzer  阅读(118)  评论(0编辑  收藏  举报