http://poj.org/problem?id=2010
"Moo U"大学有一种非常严格的入学考试(CSAT) ,每头小牛都会有一个得分。然而,"Moo U"大学学费非常昂贵,并非每一头小牛都能支付的起,很多小牛都需要经济援助,但是学校只有有限的资金F。
"Moo U"大学只会从C个学生里选N个学生出来,(N是奇数),但是希望N头小牛CSAT得分的中位数越高越好。输入N,C,F 接下来C行,每行包括一个得分和需要申请的经济援助,输出符合条件的最大中位数。
首先对score排序,然后用堆维护前k小的数的和,左右扫描预处理,枚举中位数的位置。
就是把每个数i的前n/2个数的最小和求出来用sum1[i]保存,i的后n/2个数的最小和求出来用sum2[i]保存。
枚举中位数的时候只需要逆序枚举 p[i]+sum1[i]+sum2[i]<=F 满足条件的 i,输出中位数即可。
1 #include <cstdio> 2 #include <queue> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 100010; 7 int N,C,F; 8 struct node 9 { 10 int s,c; 11 bool operator < (const node &a) const //定义堆的优先级 为大根堆 12 { 13 return c<a.c; 14 } 15 }p[maxn]; 16 17 bool cmp(const node& x,const node& y) //按score排序 18 { 19 return x.s<y.s; 20 } 21 priority_queue<node>q1,q2; 22 int f1[maxn],f2[maxn]; 23 void solve() 24 { 25 sort(p,p+C,cmp); 26 int sum1=0,sum2=0; 27 int ans=-1; //没有符合条件的输出-1 28 memset(f1,0,sizeof(f1)); 29 memset(f2,0,sizeof(f2)); 30 for(int i=0;i<C;i++) 31 { 32 if(i<N/2) // i<N/2的时候 这个i不能选 33 { 34 q1.push(p[i]); 35 sum1+=p[i].c; 36 continue; 37 } 38 f1[i]=sum1; //i之前的n/2的最小值 39 if(p[i].c>=q1.top().c) continue; 40 sum1-=q1.top().c; //如果i比当前堆中最大元素小,需要更新 41 q1.pop(); 42 sum1+=p[i].c; 43 q1.push(p[i]); 44 } 45 for(int i=C-1;i>=0;i--) 46 { 47 if(i>C-1-N/2) 48 { 49 q2.push(p[i]); 50 sum2+=p[i].c; 51 continue; 52 } 53 f2[i]=sum2; 54 if(p[i].c>=q2.top().c) continue; 55 sum2-=q2.top().c; 56 q2.pop(); 57 sum2+=p[i].c; 58 q2.push(p[i]); 59 } 60 for(int i=C-1-N/2;i>=N/2;i--) 61 { 62 if(f1[i]+f2[i]+p[i].c<=F) 63 { 64 ans=p[i].s;break; 65 } 66 } 67 printf("%d ",ans); 68 } 69 int main() 70 { 71 while(~scanf("%d%d%d",&N,&C,&F)) 72 { 73 for(int i=0;i<C;i++) 74 scanf("%d%d",&p[i].s,&p[i].c); 75 solve(); 76 } 77 return 0; 78 }