codeforces 725D Contest Balloons

本文介绍了一种通过赠送气球使对手无法参与排名的竞争策略。采用贪心算法和优先队列,快速找到最佳目标,提升自身排名。文章详细解释了算法实现及优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意很容易理解:Limak可以把自己获得的气球送给别人,使别人的气球大于体重。从而让别人漂浮的天花板上,不能参与排名,从而使Limak自己的排名上升。这个题目是一个典型的贪心,当Limak把自己的气球给别人的时候,他自己的手中的气球就会减少,那么他自己的排名也是有可能降低的。那么,我们就需要思考,Limak应该把气球给什么样的人,他自己的排名才有可能上升。其实,很简单,他肯定是把气球给当前排名在自己前面的人,自己的排名才能上升。那么,问题又来了,他前面的人有很多,到底给哪一个人呢?仔细想一想,他只需要给一个上升至天花板所需要气球最少的即可。Limak每次把气球给别人后,自己的气球数发生了变化,而且也可能会导致一些以前排名在Limak之后的,现在跑到Limak前面。这样以来,每次Limak让一个人上升至天花板后,就需要更新各个选手的排名。那么,关键的问题来了,由于数据量比较大,每次如何快速的找到一个当前排名在Limak前面,且上升至天花板所需的气球最少的选手?我使用了优先队列(重定义小于号,使上升至天花板所需的气球最少的在队首部)保存当前比Limak大的选手即可,这样就能是查找时间为lg(n)。最终的答案为,在处理过程中,队列中的元素最少的时侯,就是Limak排名最靠前的时候。具体的实现如下:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define ll long long 

using namespace std;

const int MAX = 300010;

struct Node{
	ll t, w, x;
	bool operator < (const Node& args) const{
		return x > args.x;
	}
}a[MAX], b[MAX], first;


void merge_sort(int l, int r){
	if (l >= r){
		return;
	}

	int mid = (l+r) / 2;

	merge_sort(l, mid);
	merge_sort(mid+1, r);

	int x = l, y = mid+1, i = l;

	while (x <= mid || y <= r){
		if (x <= mid && (y > r || a[x].t >= a[y].t)){
			b[i++] = a[x++];
		}else {
			b[i++] = a[y++];
		}
	}

	for (i = l; i<=r; i++){
		a[i] = b[i];
	}
}

priority_queue<Node> q;

void init(){
	while (!q.empty())q.pop();
}

int solve(int n){

	int m, res = 0, ans = MAX;
	for (m = 0; m<n-1; m++){
		if (a[m].t > first.t){
			q.push(a[m]);
			res++;
		}else{
			break;
		}
	}

	ans = min(ans, res);

	while (!q.empty()){
		Node tmp = q.top();

		if (tmp.x <= first.t){
			q.pop();
			first.t -= tmp.x;
			res--;

			for (; m<n-1; m++){
				if (a[m].t > first.t){
					q.push(a[m]);
					res++;
				}else{
					break;
				}
			}

			ans = min(ans, res);
		}else{
			break;
		}
	}

	ans = min(ans, res);

	return ans+1;
}

int main(){
	int n;
	while (scanf("%d", &n) != EOF){
		init();

		scanf("%lld%lld", &first.t, &first.w);

		for (int i = 0; i<n-1; i++){
			scanf("%lld%lld", &a[i].t, &a[i].w);
			a[i].x = a[i].w-a[i].t+1;
		}

		merge_sort(0, n-2);
 

		printf("%d\n", solve(n));
	}


	return 0;




}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值