【USACO】2004 Mar finance 赞助学费

奶牛贝西创办的哞哞大学面临选拔优秀奶牛入学的挑战。面对有限的助学基金,需要确定接受哪些奶牛的申请,使得CSAT成绩的中位数最大。输入包含申请奶牛数量、奖学金需求和基金总额,输出最大可能的中位数或-1表示无法资助。解决方案涉及排序和动态规划,使用大根堆维护前N/2个最小花费和后N/2个最小花费,找到满足条件的最低总花费。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

finance 赞助学费


  • Description

人类可以选择很多大学,而奶牛们却没学可上。为解决这个问题,贝西和她的伙伴们创立了一所奶牛大学,取名为哞哞大学。
为了选拔优秀学生,她们发明了一种奶牛学术能力测试(简称 CSAT),这种测试的分数异常精确,每头奶牛的成绩可以用0到2 × 10^9之间的一个整数表示,而且可以保证每头奶牛的分数都不同。
哞哞大学的学费很贵,奶牛们表示负担不起,他们都各自申请了奖学金。政府并没有为奶牛准备奖学金,所有的预算都必须要从学校有限的助学基金中扣除(设基金总额为F)。
哞哞大学有N间宿舍,N是一个奇数,所以贝西只能接受N头奶牛的申请,她发誓不会让入学的奶牛少于N。此外,她希望新生的 CSAT 成绩表现优异,她以中位数来衡量新生的总体水平。所谓中位数,就是排序后处在最中间的分数,比如3,8,9,7,5的中位数是7。
今年,共有C头奶牛申请入学,给定每头奶牛的 CSAT成绩和申请的奖学金数目,以及学校可赞助的总额,确定贝西接受哪些奶牛的申请才可以使成绩的中位数达到最大。

  • Input Format

第一行:三个用空格分开的整数:N,C和F。1 ≤ N ≤ 19999,N ≤ C ≤ 10^5,0 ≤ F ≤ 2 × 10^9
第二行到C + 1行:每行有两个用空格分开的整数。第一个数是这头奶牛的 CSAT 成绩, 第二个数是这头奶牛需要的奖学金Qi,0 ≤ Qi ≤ 10^5。

  • Output Format

第一行:一个整数,表示贝西可以得到的最大中位数,如果现有基金不够资助任何N头奶牛,则输出-1。

  • Sample Input

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

  • Sample Output

35

  • Hint

样例解释:贝西接受 CSAT分数为5,35,50的奶牛的申请,中位数为 35,需支付的奖学金总额为18 + 30 + 21 = 69。


  • 分析

由于一个物品有两个属性,所以我们考虑先按CSAT排序,如果以i为中位数,则i前后各有N/2个。然后我们用F[i]表示1~i取N/2个最小花费,G[i]表示i~C取N/2个最小花费。然后从后找一个Q[i]+F[i-1]+G[i+1]小于F的就可以了。
至于维护F和G,我们开个大根堆记录当前最小的N/2个,然后每次把Q[i]与堆顶比较取最小的即可。(详见代码)


#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int N,C,f,F[100005],G[100005];
struct Data{int CSAT,Q;}A[100005];
inline bool cmp (const Data&A,const Data&B){return A.CSAT<B.CSAT;}
priority_queue <Data> Q1,Q2;
inline bool operator < (Data A,Data B){return A.Q<B.Q;}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    scanf("%d%d%d",&N,&C,&f);
    for (int i=1;i<=C;i++) scanf("%d%d",&A[i].CSAT,&A[i].Q);
    sort(A+1,A+1+C,cmp);
    for (int i=1,j=C;i<=N/2;i++,j--){
        Q1.push(A[i]),F[N/2]+=A[i].Q,Q2.push(A[j]),G[C-N/2+1]+=A[j].Q;
    }
    for (int i=N/2+1,j=C-N/2;i<=C-N/2-1;i++,j--){
        if (Q1.top().Q>A[i].Q) F[i]=F[i-1]-Q1.top().Q+A[i].Q,Q1.pop(),Q1.push(A[i]);
        else F[i]=F[i-1];
        if (Q2.top().Q>A[j].Q) G[j]=G[j+1]-Q2.top().Q+A[j].Q,Q2.pop(),Q2.push(A[j]);
        else G[j]=G[j+1];
    }
    for (int i=C-N/2;i>=N/2+1;i--)
        if (A[i].Q+F[i-1]+G[i+1]<=f){
            printf("%d",A[i].CSAT);
            fclose(stdin); fclose(stdout);
            return 0;
        }
    printf("-1");
    fclose(stdin); fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值