引用来自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;
}