POJ 2010 Moo University

题意:给你c头牛,并给出每头牛的分数和花费,要求你找出其中n(n为奇数)头牛,并使这n头牛的分数的中位数尽可能大,同时这n头牛的总花费不能超过f,否则输出-1.

思路:首先对n头牛按分数进行排序,然后假设当前这头牛X的分数为中位数,然后求出X前面n/2头牛的最小花费和,以及后面n/2头牛的最小花费和。

   因为按分数排序,X的前n/2和后n/2的牛的分数肯定分别大于等于X和小于等于X,所以X的分数肯定会是中位数。

   所以,我们令left[i]为牛i的前n/2头牛的最小花费和,right[i]为牛i的后n/2头牛的最小花费和,然后i从c-1到0遍历,求出第一个头牛的left[i]+right[i]+X的花费 ≤ f,该头牛的分数就是所求出的最大中位数。

AC代码:

#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int MAX_N = 100005;
int n,c,f, left[MAX_N], right[MAX_N], half,total,result;
pair<int, int> w[MAX_N];
void solve()
{
	half = n/2;
	total = 0;
	
	priority_queue<int> q;
	for(int i = 0; i < c; i++)
	{
		left[i] = q.size() == half ? total : 0x3f3f3f3f;
		q.push(w[i].second);
		total += w[i].second;
		
		if(q.size() > half)
		{
			total -= q.top();
			q.pop();
		}
	}
	
	total = 0;
	while(!q.empty()) q.pop();
	for(int i = c-1; i >= 0; i--)
	{
		right[i] = q.size() == half ? total : 0x3f3f3f3f;
		q.push(w[i].second);
		total += w[i].second;
		if(q.size() > half)
		{
			total -= q.top();
			q.pop();
		}
	}
	
	result = -1;
	for(int i = c-1; i >= 0; i--)
	{
		int x = left[i] + w[i].second + right[i];
		if(x <= f)
		{
			result = w[i].first;
			break;
		}
	}
	printf("%d
", result);
}
int main()
{
	scanf("%d %d %d", &n, &c, &f);
	for(int i = 0; i < c; i++)
		scanf("%d %d", &w[i].first, &w[i].second);
	sort(w,w+c);
	solve();
	return 0;
}

  

原文地址:https://www.cnblogs.com/sevenun/p/5477993.html