一个很水的题,可是遇到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;
}