POJ 2010- Moo University - Financial Aid

引用来自http://www.cnblogs.com/iiyiyi/p/4738644.html的思路:
【题目大意】

给出C头奶牛的SAT成绩和申请奖学金,选出N头牛,使得总奖学金在≤F的情况下奶牛SAT成绩的中位数最大。

【思路】
假设before[i]表示前i头奶牛中n/2头奶牛奖学金总额的最小值,而after[i]表示后i头奶牛中n/2头奶牛奖学金总额的最小值。
将C头奶牛按照SAT成绩进行排序后,从第c-n/2头开始到第n/2+1头奶牛进行枚举,如果当前before[i]+after[i]+当前奶牛申请的奖学金≤F,则退出,当前奶牛SAT成绩就是中位数的最大值。那么如何求before和after呢?可以用优先队列进行预处理。
以before为例,每新加入一头奶牛,就把它申请的奖学金累加到sum中去。如果当前优先队列的size大于n/2,则让队首(即申请奖学金最多的那一个)出队。这样,sum的总和始终未前i头奶牛中,n/2头奶牛奖学金总和的最小值。after同理从后往前做即可。

【错误点】
不要忘记了有可能是无解的,要输出-1;其次由于数组下标是0开始的,注意循环是[c-1-n/2,n/2]。
看discuss区有人说有多组数据,不写while会出错。(然而事实上并不是 摊手)


#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
struct Cows{
	int CSAT,aid; 
}cow[100005];
bool cmp(Cows a,Cows b) {return a.CSAT<b.CSAT;}
int main()
{
	int n,c,f,before[100005],after[100005];
	scanf("%d%d%d",&n,&c,&f);
	for(int i=1;i<=c;i++) scanf("%d%d",&cow[i].CSAT,&cow[i].aid);
	sort(cow+1,cow+c+1,cmp);
	int num=n/2,sum=0;//收n头牛,去掉中位数之后,剩下的左边有num头,右边也有num头
	priority_queue<int> q1;
	for(int i=1;i<=c;i++)//寻找在cow[i]之前的最小aid和,存入before[i]
	{
		sum+=cow[i].aid;
		q1.push(cow[i].aid);
		if(q1.size() > num)
		{
			sum-=q1.top();
			q1.pop();
		}
		if(q1.size() == num) before[i]=sum;
	}
	priority_queue<int> q2;
	sum=0;
	for(int i=c;i>=1;i--)//寻找在cow[i]之后的最小aid和,存入after[i]
	{
		sum+=cow[i].aid;
		q2.push(cow[i].aid);
		if(q2.size() > num)
		{
			sum-=q2.top();
			q2.pop();
		}
		if(q2.size() == num) after[i]=sum;
	}
	for(int i=c-num;i>num;i--)
	{
		if(before[i-1] + cow[i].aid + after[i+1] <= f){
			printf("%d\n",cow[i].CSAT);
			return 0;
		}
	}
	printf("-1\n");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值