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;
}

 

posted @ 2012-08-07 20:56  'wind  阅读(257)  评论(0编辑  收藏  举报