P3963 [TJOI2013] 奖学金

知识点:优先队列

难度:5

这个题可以用优先队列解决,首先一个很自然的想法我们就是先按照成绩排序,这个时候找满足的成绩,因为题目说的输入的n一定是奇数,我们不用考虑偶数的情况,接着就是重点了,我们可以从左往右扫描一遍,从右往左扫描一遍,每次扫描维护一个大根堆,里面存的是不超过n/2个最小的值,就这样来更新每个点左边/右边最小的n/2个数,以及它们的和,最后,我们再从大往小扫描一遍,找到某个点它的奖学金加上左边加上右边,小于等于题目要求的f,那么这个题就找到答案了,否则就是输出-1,剩下的就是一些编程的细节需要注意

一开始用的二分,直接二分的成绩,但是这个后来发现是没有单调性的,结果这样子写的居然还过了,真的是神奇

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 2e5 + 5;

ll L[N], R[N];
pair<ll, ll> a[N];

int main() {
	int n, c;
	ll f;
	cin >> n >> c >> f;
	for (int i = 1; i <= c; i++) {
		cin >> a[i].first >> a[i].second;
	}
	sort(a + 1, a + c + 1);
	priority_queue<ll> q1, q2;
	ll sum = 0;
	for (int i = 1; i < c; i++) {
		if ((int) q1.size() < n / 2) {
			sum += a[i].second;
			q1.push(a[i].second);
		} else if (a[i].second < q1.top()) {
			sum -= q1.top(); q1.pop();
			sum += a[i].second;
			q1.push(a[i].second);
		}
		L[i + 1] = sum;
	}
	sum = 0;
	for (int i = c; i > 1; i--) {
		if ((int) q2.size() < n / 2) {
			sum += a[i].second;
			q2.push(a[i].second);
		} else if (a[i].second < q2.top()) {
			sum -= q2.top(); q2.pop();
			sum += a[i].second;
			q2.push(a[i].second);
		}
		R[i - 1] = sum;
	}
	int ans = -1;
	for (int i = c - n / 2; i >= 1 + n / 2; i--) {
		if (L[i] + R[i] + a[i].second <= f) { ans = a[i].first; break; }
	}
	cout << ans;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值