POJ2010 Moo University - Financial Aid

题意:奶牛学校招生,c头奶牛报名,要选n头(n为奇数),学校是义务制,所以每头奶牛的学费都由学校负责。每头奶牛都由自己的考试分数和它需要花的学费,学校总共有f的资金,问合法招生方案中中间分数(即排名第(n+1)/2)最高的是多少。

题解:先将所有的奶牛按照分数由高到低排序,假设k是招的奶牛中排名中间的那头,按照排序可知,[1,k-1]中的奶牛必定被招了(n-1)/2头,[k+1,c]中也必定被招了(n-1)/2头,而且无论招的是谁,分数是怎么样,最后影响结果的都只是k的分数。于是,可以预处理dpl[i]代表[1,i]头牛中选出(n-1)/2头牛的最小花费,dpr[i]代表[i,c]头牛中选出(n-1)/2头牛的花费,预处理方法可以用一个大顶堆,复杂度nlogn,最后枚举中间牛复杂度n。

 

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN=111111;
priority_queue<int> Q;
int dpl[MAXN];
int dpr[MAXN];
struct eg
{
	int a,b;
}cow[MAXN];
bool cmp(const eg&a,const eg&b)
{
    if(a.a!=b.a)
        return a.a>b.a;
    return a.b<b.b;
}
int main()
{
	#ifndef ONLINE_JUDGE
		freopen("G:/1.txt","r",stdin);
		freopen("G:/2.txt","w",stdout);
	#endif
	int n,c,f;
	scanf("%d%d%d",&n,&c,&f);
	for(int i=1;i<=c;i++)
		scanf("%d%d",&cow[i].a,&cow[i].b);
	sort(cow+1,cow+c+1,cmp);
	int nu=(n-1)/2;
	int sum=0;
	for(int i=1;i<=nu;i++)
	{
		Q.push(cow[i].b);
		sum+=cow[i].b;
	}
	dpl[nu]=sum;
	for(int i=nu+1;i<=c;i++)
	{
		if(cow[i].b>Q.top())
		{
			dpl[i]=sum;
		}
		else
		{
			sum=sum-Q.top()+cow[i].b;
			Q.pop();
			Q.push(cow[i].b);
			dpl[i]=sum;
		}
	}
	sum=0;
	while(!Q.empty())
		Q.pop();
	for(int i=c;i>=c-nu+1;i--)
	{
		Q.push(cow[i].b);
		sum+=cow[i].b;
	}
	dpr[c-nu+1]=sum;
	for(int i=c-nu;i>=1;i--)
	{
		if(cow[i].b>Q.top())
		{
			dpr[i]=sum;
		}
		else
		{
			sum=sum-Q.top()+cow[i].b;
			Q.pop();
			Q.push(cow[i].b);
			dpl[i]=sum;
		}
	}
	bool flag=false;
	for(int i=nu+1;i<=c-nu;i++)
	{
		if(cow[i].b+dpl[i-1]+dpr[i+1]<=f)
		{
			flag=true;
			printf("%d\n",cow[i].a);
			break;
		}
	}
	if(!flag)
		printf("-1\n");
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值