Moo University - Financial Aid(2010)

一个很水的题,可是遇到sb一样的我后,它就不简单了,跪了。。。

大致题意:n, m, f,从m个组中选出n组,要求这n组的第二项的加起来的和不超过f,求所有满足的情况中,中位数最大为多少。

方法:先将这些按照第一项的从小到大排序,然后用二分的方法来确定中位数(要注意范围,只有从n/2+1~m-n/2之间的可以),每当确定一个temp后, 判断可不可以,如果可以的话,就说明可以向后找,不然的话,就要向上找,至于怎么判定可不可以,先用优先队列,将所有的组放进去,然后依次取出来,如果取出的第一项的值小于temp的第一项并且小于的个数小于n/2的话,就加进来,同理如果大于第一项的话,也要加进来,如果相同的话,不用考虑相同的个数,因为,只要小于的个数小于n/2和大于的个数也小于n/2,那么就可以了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
struct s{
    __int64 val, cost;
    s(){}
    s(__int64 tt, __int64 dd):val(tt), cost(dd){}
    bool operator < (const s &a) const{
        return cost > a.cost;
    }
}pp[100100];
bool cmp(s a, s b){
    return a.val < b.val;
}
__int64 n, m, lim;
priority_queue<s>que;
bool judge(__int64 xx, __int64 yy){
    int i;
    while(!que.empty())
        que.pop();
    for(i = 1; i <= m; i++)
        que.push(s(pp[i].val, pp[i].cost));
    int cont1, cont2, cont3;
    cont1 = cont2 = cont3 = 0;
    __int64 sum = 0;
    while(!que.empty()){
        s temp = que.top();
        que.pop();
        if(temp.val < xx && cont1 < n/2){
            cont1++;
            sum += temp.cost;
        }
        else if(temp.val == xx){
            cont2++;
            sum += temp.cost;
        }
        else if(temp.val > xx && cont3 < n/2){
            cont3++;
            sum += temp.cost;
        }
        if(sum > lim)
            return false;
        if(cont1+cont2+cont3 == n)
            return true;
    }
    return false;
}
int main(){
    int i;
    while(scanf("%I64d%I64d%I64d", &n, &m, &lim) == 3){
        while(!que.empty()) que.pop();
        for(i = 1; i <= m; i++)
            scanf("%I64d%I64d", &pp[i].val, &pp[i].cost);
        sort(pp+1, pp+1+m, cmp);
        int l = n/2+1;
        int r = m - n/2;
        __int64 res = -1;
        while(l <= r){
            int mid = (l+r) / 2;
            if(judge(pp[mid].val, pp[mid].cost)){
                res = pp[mid].val;
                l = mid + 1;
            }
            else
                r = mid - 1;
        }
        printf("%I64d\n", res);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值