题目大意
有
n
n
n个员工,需要给他们发工资,每个人的工资可以维区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]中的任意一个数。
求在发的工资总和不超过
s
s
s的情况下,最大的中位数是多少。
时间限制
3s
数据范围
n
≤
2
×
1
0
5
n\le 2\times10^5
n≤2×105,
n
n
n为奇数
s
≤
2
×
1
0
14
s\le2\times10^{14}
s≤2×1014
题解
不妨记
n
=
2
×
m
+
1
n = 2\times m + 1
n=2×m+1
不妨设中位数为
m
i
d
mid
mid,那么
m
i
d
mid
mid要满足什么条件呢?
显然有
m
m
m个数大于或等于
m
i
d
mid
mid。
而现在是对于总金额是有限制的,因此一种贪心的思想,就是前
m
m
m个数能多小就多小,后面
m
+
1
m+1
m+1个数都为
m
i
d
mid
mid(除了
l
i
>
m
i
d
l_i > mid
li>mid外)。
显然答案也是满足二分性的,因此,二分答案,贪心判断。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#define G getchar
#define ll long long
using namespace std;
ll read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
ll n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 200005;
int l , r , mid , n , ans , m;
ll s , sum;
struct node
{
int l , r;
bool operator < (const node &n)const
{
return l > n.l;
}
}a[N];
void work(int mid)
{
for (int i = 1 ; i <= n ; i++)
if (a[i].r >= mid && m)
{
m--;
s = s + max(mid , a[i].l);
}
else s = s + a[i].l;
}
int main()
{
//freopen("e.in","r",stdin);
//freopen("e.out","w",stdout);
for (int t = read() ; t ; t--)
{
scanf("%d%lld", &n , &sum);
l = r = 1;
for (int i = 1 ; i <= n ; i++)
{
a[i].l = read();
a[i].r = read();
r = max(r , a[i].r);
}
sort(a + 1 , a + 1 + n);
for ( ; l < r ;)
{
mid = (l + r) / 2;
m = (n + 1) / 2;
s = 0;
work(mid);
if (s <= sum && m == 0)
{
ans = mid;
l = mid + 1;
} else r = mid;
}
for ( ; ; )
{
m = (n + 1) / 2;
s = 0;
work(ans + 1);
if (s <= sum && m == 0) ans++; else break;
}
printf("%d\n", ans);
}
return 0;
}