>Link
ybtoj求中位数
>Description
给定 n 个数,求这 n 个数两两的差值(共 n ∗ ( n − 1 ) 2 \frac{n*(n-1)}{2} 2n∗(n−1) 个)的中位数。
n ≤ 2 ∗ 1 0 5 , a i ≤ 2 31 − 1 n \le 2*10^5,a_i\le2^{31}-1 n≤2∗105,ai≤231−1
>解题思路
考虑二分答案
二分一个中位数 x x x,我们判断有多少差值小于等于 x x x
可以先对 a a a 排个序,然后对于每一个数,往后找差值小于等于 x x x 的数有多少个,同样二分解决
时间复杂度 O ( 31 ∗ n l o g n ) O(31*nlogn) O(31∗nlogn)
之前我打二分都是ans取mid的min值,不知道为什么这道题不行(改了好久TT),要直接把mid赋值给ans
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
#define inf 20000000
#define LL long long
using namespace std;
LL n, m, pos, a[N], ans, ans1, ans2;
bool check (LL x)
{
LL cnt = 0, p;
for (LL i = 1; i <= n; i++)
{
p = upper_bound (a + 1, a + 1 + n, a[i] + x) - a - 1;
if (i < p && p <= n) cnt += p - i;
if (cnt >= pos) return 1;
}
if (cnt >= pos) return 1;
return 0;
}
int main()
{
freopen ("mid.in", "r", stdin);
freopen ("mid.out", "w", stdout);
LL l, r, mid;
scanf ("%lld", &n);
m = n * (n - (LL)1) / (LL)2;
for (LL i = 1; i <= n; i++) scanf ("%lld", &a[i]);
sort (a + 1, a + 1 + n);
if (m & 1)
{
pos = m / (LL)2 + (LL)1;
l = 0, r = a[n];
while (l <= r)
{
mid = (l + r) / (LL)2;
if (check (mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf ("%lld", ans);
}
else
{
pos = m / (LL)2;
l = 0, r = a[n];
while (l <= r)
{
mid = (l + r) / (LL)2;
if (check (mid)) ans1 = mid, r = mid - 1;
else l = mid + 1;
}
pos = m / (LL)2 + (LL)1;
l = 0, r = a[n];
while (l <= r)
{
mid = (l + r) / (LL)2;
if (check (mid)) ans2 = mid, r = mid - 1;
else l = mid + 1;
}
printf ("%lld", (ans1 + ans2) / (LL)2);
}
return 0;
}