题目大意:有C头牛,每头牛都有相应的分数和需求,要求在这C头牛中选出N头,使得这N头牛中的分数的中位数达到最大,且需求之和小于等于F
解题思路:先按成绩排序
再用两个数组保留最小需求之和
left数组保留第i个位置左边的 N/2个最小需求之和
right数组保留第i个位置右边的 N/2个最小需求之和
如何保留最小的需求之和呢,扫描两遍(左右),用优先队列保留N / 2个最小需求
最后只需要判断一下 left[i] + right[i] + 第i头牛的需求 <= F就可以了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 100010
typedef long long ll;
struct Cows{
ll score, aid;
}cow[maxn];
int N, C;
ll F, left[maxn], right[maxn];
bool cmp(const Cows a, const Cows b) {
return a.score < b.score;
}
void solve() {
sort(cow, cow + C, cmp);
for(int i = 0; i < C; i++)
left[i] = right[i] = 0;
priority_queue<ll> pq;
ll sum1 = 0;
for(int i = 0; i < C; i++) {
if(i < N / 2) {
pq.push(cow[i].aid);
sum1 += cow[i].aid;
continue;
}
left[i] = sum1;
if(cow[i].aid >= pq.top())
continue;
sum1 -= pq.top();
pq.pop();
sum1 += cow[i].aid;
pq.push(cow[i].aid);
}
while(!pq.empty())
pq.pop();
sum1 = 0;
for(int i = C - 1; i >= 0; i--) {
if(i > C - 1 - N / 2) {
sum1 += cow[i].aid;
pq.push(cow[i].aid);
continue;
}
right[i] = sum1;
if(cow[i].aid >= pq.top())
continue;
sum1 -= pq.top();
pq.pop();
sum1 += cow[i].aid;
pq.push(cow[i].aid);
}
ll ans = -1;
for(int i = N / 2; i <= C - 1 - N / 2; i++)
if(left[i] + right[i] + cow[i].aid <= F)
ans = cow[i].score;
printf("%lld\n", ans);
}
int main(){
while(scanf("%d%d%lld",&N, &C, &F) != EOF) {
for(int i = 0; i < C; i++)
scanf("%lld%lld", &cow[i].score, &cow[i].aid);
solve();
}
return 0;
}
时间: 2024-10-08 11:04:08