poj 3579 二分+lower_bound

来源:互联网 发布:三网通彩信软件 编辑:程序博客网 时间:2024/05/29 05:01

题意:

给n个数字组成的序列,求| Xi - Xj | ( 0 <= i < j < n) 的中位数是多少。

n(100000),X(1000000000)。


解析:

n灰常大,所以普通枚举不行。

所以先二分中位数是多少。

然后将X排个序,然后可以二分出比(mi + Xi)大的数有多少个,代表了差值中比中位数大的数有多少个。

然后若个数 < C(n, 2), 说明比中位数大的数少了,说明中位数太大了。

二分15次就可以得到答案了,50次的话差不多TLE那样。


代码:


#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <set>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 1e5 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);int n;LL x[maxn];LL d;bool ok(LL mi){    LL cnt = 0;    for (int i = 0; i < n; i++)    {        cnt += n - (lower_bound(x + i, x + n, x[i] + mi) - x);    }    return cnt <= d / 2;}int main(){    #ifdef LOCAL    freopen("in.txt", "r", stdin);    #endif // LOCAL    while (~scanf("%d", &n))    {        LL lo = 0, hi = 0;        for (int i = 0; i < n; i++)        {            scanf("%lld", &x[i]);            hi = hi < x[i] ? x[i] : hi;        }        sort(x, x + n);        d = (n * (n - 1)) >> 1;        for (int i = 0; i < 15; i++)        {            LL mi = (lo + hi) >> 1;            if (ok(mi))                hi = mi;            else                lo = mi;        }        printf("%lld\n", lo);    }    return 0;}

0 0