挑战程序设计竞赛2.4习题:Moo University - Financial Aid POJ - 2010

Bessie noted that although humans have many universities they can attend, cows have none. To remedy this problem, she and her fellow cows formed a new university called The University of Wisconsin-Farmside,"Moo U" for short.

Not wishing to admit dumber-than-average cows, the founders created an incredibly precise admission exam called the Cow Scholastic Aptitude Test (CSAT) that yields scores in the range 1..2,000,000,000.

Moo U is very expensive to attend; not all calves can afford it.In fact, most calves need some sort of financial aid (0 <= aid <=100,000). The government does not provide scholarships to calves,so all the money must come from the university's limited fund (whose total money is F, 0 <= F <= 2,000,000,000).

Worse still, Moo U only has classrooms for an odd number N (1 <= N <= 19,999) of the C (N <= C <= 100,000) calves who have applied.Bessie wants to admit exactly N calves in order to maximize educational opportunity. She still wants the median CSAT score of the admitted calves to be as high as possible.

Recall that the median of a set of integers whose size is odd is the middle value when they are sorted. For example, the median of the set {3, 8, 9, 7, 5} is 7, as there are exactly two values above 7 and exactly two values below it.

Given the score and required financial aid for each calf that applies, the total number of calves to accept, and the total amount of money Bessie has for financial aid, determine the maximum median score Bessie can obtain by carefully admitting an optimal set of calves.

Input

* Line 1: Three space-separated integers N, C, and F

* Lines 2..C+1: Two space-separated integers per line. The first is the calf's CSAT score; the second integer is the required amount of financial aid the calf needs

Output

* Line 1: A single integer, the maximum median score that Bessie can achieve. If there is insufficient money to admit N calves,output -1.

Sample Input

3 5 70
30 25
50 21
20 20
5 18
35 30

Sample Output

35

Hint

Sample output:If Bessie accepts the calves with CSAT scores of 5, 35, and 50, the median is 35. The total financial aid required is 18 + 30 + 21 = 69 <= 70.
注意点,由于分数区间过大,没有办法dp实现,只能从个数等数量级少的入手。
想到要求出中位数,中间值难求,不知道,但是我们知道中间值有范围,我们先按照分数排序
由于中位数之前有n/2个数,之后也有n/2个数,不如直接遍历中位数的所有可能,求出前n/2的最小和以及后n/2的最小和,两者加上中位数的值如果小于f,那么就有可能选中,答案就是在可能选中的当中中位数最大的那个。
于是乎我们知道中位数在排序后cows[n/2] ~ cows[c - n/2]的范围内(数组从0开始到n-1结束),每一种情况计算前后选取n/2个分别使得前后选取的n/2个的和最小。
如果中位数是cows[n/2](也就是中位数可取范围的最小那个)那么中位数之前一共有n/2的数,所有在中位数之前选取n/2个数就只能是把之前的全选,和为他们的和。如果中位数往后一个(也就是可选范围第二小的),那么中位数之前一共有n/2+1个数,我们要选取其中n/2个数使得这些数和最小,我们可以从上一个状态推出答案——因为上一个状态是全选,我们这次会多一个数剩余,我们肯定要剩余需要资助最多的奶牛,我们比较比上一次新增的cows[n/2]奶牛的花费与之前n/2个中需要资助最大的奶牛的花费进行比较,看看哪个大。如果前者大,我们就留下新增的那头奶牛不选,因为它的花费比cows[0]~cows[n/2-1]中任何一头奶牛所要的资费都要大;如果后者大,那么把之前状态中n/2个中需要最大资助的奶牛不要,少的一个我们就换成cows[n/2]这个新增的奶牛就可以使得前面选取n/2的和最少,以此类推,每次都找到上一次选择的n/2个中最大的与新增的进行比较进行替换,为了节省时间和不必要的开支,之前的状态可以用数据结构进行保存,为了方便找到最大值,我们采用优先队列进行维护。
AC代码:
#include <stdio.h>
#include <queue>
#include <algorithm>
using namespace std;
struct Cow{
	int score;
	int need;
	friend bool operator<(Cow x, Cow y)
	{
		return x.score < y.score;
	} 
}cows[100005];//记录奶牛状态,score分数,need需要的资助金额
priority_queue<int> pq_pre, pq_pos;//pq_pre:从中位数之前取n/2个数,使得资助金额和最小的优先队列,pq_pos从中位数之后取n/2个数
int pre[100005];//在中位数为i的时候,从i之前取n/2个数,使得资助金额和最小的值
int pos[100005];
int total, ans = -1;//如果答案不存在就是-1,total是中间变量,计算pre或者是pos的值的
int cow_num;//单纯的计数功能
int main(void)
{
	int n, c, f;
	scanf("%d %d %d", &n, &c, &f);
	for(int i = 0; i < c; i++)
	{
		scanf("%d %d", &cows[i].score, &cows[i].need);	
	}
	sort(cows, cows + c);//按分数排序
	for(int i = 0; i < n / 2; i++)//初始化把前n/2个都加起来,也就是当中位数为从cows[n/2].need时前面n/2的和的最小值
	{
		total += cows[i].need;
		pq_pre.push(cows[i].need);//记得前面的也要放进队列
	}
	for(int i = n / 2; i < c - n / 2; i++)
	{
		pre[i] = total;
		if(!pq_pre.empty() && cows[i].need < pq_pre.top())//如果队列为非空(防止c == 1的情况)且新增的奶牛比在队列的资助最大奶牛的资助要小,那么就删掉之前队列最大的,换上这一头新的奶牛
		{
			total -= pq_pre.top();
			pq_pre.pop();
			total += cows[i].need;
			pq_pre.push(cows[i].need);
		}
	}
	total = 0;
	for(int i = c - 1; i >= c - n / 2; i--)//同理计算当中位数为cows[c - n/2 - 1]时后n/2头
	{
		total += cows[i].need;
		pq_pos.push(cows[i].need);
	}
	for(int i = c - n / 2 - 1; i >= n / 2; i--)
	{
		pos[i] = total;
		if(!pq_pos.empty() && cows[i].need < pq_pos.top())
		{
			total -= pq_pos.top();
			pq_pos.pop();
			total += cows[i].need;
			pq_pos.push(cows[i].need);
		}
	}
	for(int i = c - n / 2 - 1; i >= n / 2; i--)//从大到小遍历,找到的第一个符合体条件的情况就是答案
		if(pre[i] + pos[i] + cows[i].need <= f)
		{
			ans = cows[i].score;
			break;
		}
	printf("%d\n", ans);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/jacobfun/p/12244509.html