【poj 2010】Moo University - Financial Aid 预处理dp

47 篇文章 0 订阅

题意:输入 n,c,f(要选n头牛,共有c头牛,只有 f 的资金),接下来c行每行有a,b表示第i头牛的成绩为a,需要花费b元。问你在少于f的前提下,选出n头奶牛并是排序后第(n-1)/2的奶牛成绩最好。


考虑这道题的数据范围是100000,所以正解一定是有一个log级别的,可以想到二分和堆,数据结构,据说二分是错的,但是本题可以水过,但是为了正义,还是考虑正解吧。

明确本题的两个限制条件:1.奶牛的成绩 2.奶牛的花费

但是对于选出来的n头奶牛,只有第(n-1)/2头奶牛是对答案有贡献的,其他的都只是来看戏

所以定义 dpl和dpr表示以当前奶牛为中间的牛的前后最小花费(有优先队列和dp预处理出),然后O(n)判断

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
#define maxn 101030
#define Clear(x) memset(x,0,sizeof(x))
using namespace std;
int n,c,f,dpl[maxn],dpr[maxn];
priority_queue<int>q;

struct DATA{
	int s,f;
	bool operator <(const DATA& b )const{
		return s==b.s?f<b.f:s>b.s;
	}
}cow[maxn];


int main(){
	while(scanf("%d%d%d",&n,&c,&f)!=EOF){
		
		while(!q.empty())q.pop();
		Clear(dpl);Clear(dpr);
		for(int i=1;i<=c;i++)scanf("%d%d",&cow[i].s,&cow[i].f);
		sort(cow+1,cow+1+c);
		//for(int i=1;i<=c;i++)printf("%d %d\n",cow[i].s,cow[i].f );
		int k=(n-1)/2,sum=0;
		
		for(int i=1;i<=k;i++)sum+=cow[i].f,q.push(cow[i].f);
		dpl[k+1]=sum;q.push(cow[k+1].f);sum+=cow[k+1].f;
		for(int i=k+2;i<=c-k;i++){
			sum-=q.top();q.pop();
			dpl[i]=sum;
			sum+=cow[i].f;q.push(cow[i].f);
		}
		
		while(!q.empty())q.pop();
		sum=0;
		
		for(int i=c;i>=c-k+1;i--)sum+=cow[i].f,q.push(cow[i].f);
		dpr[c-k]=sum;q.push(cow[c-k].f);sum+=cow[c-k].f;
		for(int i=c-k-1;i>k;i--){
			sum-=q.top();q.pop();
			dpr[i]=sum;
			sum+=cow[i].f;q.push(cow[i].f);
		}
		
		bool ok=false;int ans=0;
		for(int i=k+1;i<=c-k;i++){
			if(dpl[i]+dpr[i]+cow[i].f<=f){
				ok=true;
				ans=max(ans,cow[i].s);
				break;
			}
		}
		if(ok)
		printf("%d\n",ans);
		else printf("-1\n");
	}
	return 0;
}
/*
5 18
20 20
30 25
35 30
50 21
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值