大致题意 : 有n名员工, 以及总资金s, 每名员工有个薪资期望区间l,r, 对于每名需要选择发放薪资sal i, 使得每名员工的薪资中位数最大, 求这个最大的中位数
分析 : 很容易可以想到用二分来找这个答案, 关于找二分区间的单调性:
对l排序, 就可以得到最小的中位数left, 对r排序可以得到最大的中位数right, 而要找的答案mid就在left,right之间, 我们可以对这个区间进行二分.
对于每一个mid, 需要满足至少能找到k个mid使得中位数为mid(k = n/2+1, 及一半以上的薪资都大于等于k), 并且薪资和不能超过s, 从大到小进行循环, 使选择尽量小的同时满足条件, 这样才能选到最大mid.
按l进行排序, 对于l>mid的 : 无论怎么选最后的值都会大于mid, 不如选l尽量小;
对于r<mid的: 无论怎么选最后的值都会小于mid, 不如选l尽量小;
而对于l<=mid<=r的, 在k没选完的情况下尽量选择mid使结果尽量小, 当k选完时, 就可以选l使得结果尽量小, 每次check的sum(即薪资和)越小, 能选到的mid就越大, 直到找到结果
ac代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int n;
ll s;
struct Sal{
ll l,r;
}sal[N];
bool cmp(Sal a, Sal b)
{
if(a.l != b.l)
return a.l < b.l;
return a.r < b.r;
}
bool cmp1(Sal a, Sal b)
{
return a.l<b.l;
}
bool cmp2(Sal a, Sal b)
{
return a.r<b.r;
}
bool check(ll mid)
{
ll k = n/2+1, sum = 0;
for(int i = n; i>=1; i--)
{
if(sal[i].l>mid)
{
sum += sal[i].l;
k--;
}else if(sal[i].r<mid){
sum += sal[i].l;
}else{
if(k)
{
sum += mid;
k--;
}else{
sum += sal[i].l;
}
}
}
if(sum<=s && k<=0) return true;
else return false;
}
int main()
{
int T;
scanf("%d", &T);
while(T -- )
{
cin>>n>>s;
for(int i = 1; i<=n; i++) cin>>sal[i].l>>sal[i].r;
ll l,r;
sort(sal+1,sal+1+n,cmp1);
l = sal[n/2+1].l;
sort(sal+1,sal+1+n,cmp2);
r = sal[n/2+1].r;
sort(sal+1,sal+1+n,cmp);
while(l<r)
{
ll mid = l+r+1 >>1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout<<l<<endl;
}
}