POJ3579 Median(两次二分)

题目链接

Description

Given N numbers, X1, X2, … , XN, let us calculate the difference of every pair of numbers: ∣Xi - Xj∣ (1 ≤ i < j ≤ N). We can get C(N,2) differences through this work, and now your task is to find the median of the differences as quickly as you can!
Note in this problem, the median is defined as the (m/2)-th smallest number if m,the amount of the differences, is even. For example, you have to find the third smallest one in the case of m = 6.

Input

The input consists of several test cases.
In each test case, N will be given in the first line. Then N numbers are given, representing X1, X2, … , XN, ( Xi ≤ 1,000,000,000 3 ≤ N ≤ 1,00,000 )

Output

For each test case, output the median in a separate line.

Sample Input

4
1 3 2 4
3
1 10 2

Sample Output

1
8

思路

首先按照正常二分思想,我们需要通过二分来获取差值的中位数,但在检验时不容易想到方法。对于这些数而言,中位数差值的下标是可以得知的,即为(C(n,2)/2+1)/2。也就是在所有情况中,需要有这么多数目的差值小于等于中位数。我们不妨设当前中位数为x,对于n个数中的任一个,若其他数大于当前数+x,就说明他们之间的差值大于x,我们利用upper_bound函数找到排序后第一个大于的下标并减1,即可获取差值小于等于x的数量,然后累加与正确值比较即可。值得注意的是,因为题目所要求为差值的绝对值,所以可能认为这种方法情况不全。但正负的情况实际上总对称出现,若我们在计数时统一取正,则由于相互之间都会取到的原因,从而确保总数正确。(若使用lower_bound需要记住它查找的是第一个小于等于的数,所以需要将数值加1)

代码

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int mod=1e9+7;
const int maxn=1e6+5;
typedef long long ll;
int k,m,n,a[maxn];
bool check(double x)
{
    int cnt=0;
    for(int i=1;i<n;i++)
        cnt+=upper_bound(a+1+i,a+1+n,a[i]+x)-a-i-1;//upper_bound找到首个大于a[i]+x的下标,减1后再减去当前下标即可获得差值绝对值小于等于当前的数量
    if(cnt>=m)
        return true;//当前下标大于答案,说明中位数取大了
    else
        return false;
}//差值中位数下标
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        m=(n*(n-1)/2+1)/2;
        int l=0,r=a[n]-a[1];
        while(l<r)
        {
            int mid=(l+r)/2;
            if(check(mid))
                r=mid;
            else
                l=mid+1;
        }
        printf("%d\n",l);
    }
    return 0;
}

你可能感兴趣的:(POJ3579 Median(两次二分))