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会出错。(然而事实上并不是 摊手)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 using namespace std;
 5 struct Cows{
 6     int CSAT,aid; 
 7 }cow[100005];
 8 bool cmp(Cows a,Cows b) {return a.CSAT<b.CSAT;}
 9 int main()
10 {
11     int n,c,f,before[100005],after[100005];
12     scanf("%d%d%d",&n,&c,&f);
13     for(int i=1;i<=c;i++) scanf("%d%d",&cow[i].CSAT,&cow[i].aid);
14     sort(cow+1,cow+c+1,cmp);
15     int num=n/2,sum=0;//收n头牛,去掉中位数之后,剩下的左边有num头,右边也有num头
16     priority_queue<int> q1;
17     for(int i=1;i<=c;i++)//寻找在cow[i]之前的最小aid和,存入before[i]
18     {
19         sum+=cow[i].aid;
20         q1.push(cow[i].aid);
21         if(q1.size() > num)
22         {
23             sum-=q1.top();
24             q1.pop();
25         }
26         if(q1.size() == num) before[i]=sum;
27     }
28     priority_queue<int> q2;
29     sum=0;
30     for(int i=c;i>=1;i--)//寻找在cow[i]之后的最小aid和,存入after[i]
31     {
32         sum+=cow[i].aid;
33         q2.push(cow[i].aid);
34         if(q2.size() > num)
35         {
36             sum-=q2.top();
37             q2.pop();
38         }
39         if(q2.size() == num) after[i]=sum;
40     }
41     for(int i=c-num;i>num;i--)
42     {
43         if(before[i-1] + cow[i].aid + after[i+1] <= f){
44             printf("%d\n",cow[i].CSAT);
45             return 0;
46         }
47     }
48     printf("-1\n");
49     return 0;
50 }

 


 

posted @ 2017-03-30 22:15  Dilthey  阅读(204)  评论(0编辑  收藏  举报