POJ 2010 Moo University - Financial Aid【堆的应用】
题意: 给出 n 个人,知道了每个人的成绩,和每个人想要的奖学金,要求从这些学生中找出 m (奇数)个人满足选出的人的成绩的中位数最大,且这些人总的奖学金需求要
小于等于总的奖学金数。
分析: 可以先对学生按成绩降序排序,然后从 位置 m/2+1 到 N - m/2 枚举,中位数 q[i] ,因此对于枚举每个中位数只要求出左面 最小的 m/2 个数,和右面最小的 m/2 个
数,只要 left[i-1]+q[i].money+rght[i+1] <=F ,i 即为要找的学生。
left[i] 表示从 i 个位置向左的序列中最小的 m/2个数之和,对于每次出现新的 i 值,要求出 m/2 个最小的数这个过程可以建一个堆来维护,right[i]同样。
#include<stdio.h> #include<string.h> #include<stdlib.h> struct node { long long grade; long long money; }q[100005]; int cmp(const void*p1,const void*p2) { node *c=(node*)p1; node *d=(node*)p2; return d->grade-c->grade; } long long left[100005]; long long right[100005]; void swap(long long &a,long long &b) { long long t=a; a=b; b=t; } void down(int i,int n,long long a[]) { int son; for(;i<=n/2;i=son) { son=i<<1; if((son!=n)&&a[son+1]>a[son]) son=son+1; if(a[son]>a[i]) swap(a[son],a[i]); } } long long sum; long long heap[100005]; long long heap_update(int x,int n) { if(x<heap[1]) { sum-=heap[1]-x; heap[1]=x; down(1,n,heap); } return sum; } void init(long long a[],int n) { int i; for(i=n/2;i>=1;i--) down(i,n,a); } int main() { int l,r,n,m,i,j; long long F; while(scanf("%d%d%lld",&m,&n,&F)!=EOF) { for(i=1;i<=n;i++) scanf("%lld%lld",&q[i].grade,&q[i].money); l=1+m/2; r=n-m/2; qsort(q+1,n,sizeof(q[0]),cmp); sum=0; for(i=1;i<l;i++){ sum+=q[i].money; heap[i]=q[i].money; } init(heap,m/2); left[l-1]=sum; for(i=l;i<=n;i++) left[i]=heap_update(q[i].money,m/2); sum=0; for(i=n;i>r;i--){ sum+=q[i].money; heap[n-i+1]=q[i].money; } init(heap,m/2); right[r+1]=sum; for(i=r;i>=1;i--) right[i]=heap_update(q[i].money,m/2); for(i=l;i<=r;i++) if(left[i-1]+right[i+1]+q[i].money<=F) break; if(i>r) printf("-1\n"); else printf("%lld\n",q[i].grade); } return 0; }