【题目大意】
给出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<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 const int MAXC=100000+50; 7 struct node 8 { 9 int csat,req; 10 bool operator < (const node &x) const 11 { 12 return csat<x.csat; 13 } 14 }cow[MAXC]; 15 int n,c,f; 16 17 int before[MAXC],after[MAXC]; 18 19 void pretreatment() 20 { 21 priority_queue<int> be,af; 22 int sum=0; 23 for (int i=0;i<c;i++) 24 { 25 be.push(cow[i].req); 26 sum+=cow[i].req; 27 if (be.size()>n/2) 28 { 29 sum-=be.top(); 30 be.pop(); 31 } 32 if (be.size()<n/2) before[i]=0; 33 else before[i]=sum; 34 } 35 36 sum=0; 37 for (int i=c-1;i>=0;i--) 38 { 39 af.push(cow[i].req); 40 sum+=cow[i].req; 41 if (af.size()>n/2) 42 { 43 sum-=af.top(); 44 af.pop(); 45 } 46 if (af.size()<n/2) after[i]=0; 47 else after[i]=sum; 48 } 49 } 50 51 void getans() 52 { 53 int i,boolf=0; 54 for (i=c-1-n/2;i>=n/2;i--) 55 { 56 if (before[i-1]+after[i+1]+cow[i].req<=f) 57 { 58 boolf=1; 59 break; 60 } 61 } 62 if (boolf==1) 63 cout<<cow[i].csat<<endl; 64 else cout<<-1<<endl; 65 } 66 67 int main() 68 { 69 while (scanf("%d%d%d",&n,&c,&f)!=EOF) 70 { 71 for (int i=0;i<c;i++) scanf("%d%d",&cow[i].csat,&cow[i].req); 72 sort(cow,cow+c); 73 74 pretreatment(); 75 getans(); 76 } 77 return 0; 78 }