1. 程式人生 > >【二分答案+二分資料】POJ - 3579 E - Median

【二分答案+二分資料】POJ - 3579 E - Median

E - Median  POJ - 3579 

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 = 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

給你n個數,任取兩個數,算出差的絕對值,一共有(n-1)*n/2個,從小到大排列後問你最中間的數是幾

最開始跳不出n^2的思維怪圈,看了題解才知道你把這些數從小到大排列,那麼只要第i個數和此數的差>=mid,後面的所有數和此數之差都滿足,可以lower_bond出答案

那麼複雜度為O(nlognlogn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[100005];
int n,num;

bool ok(int x)
{
    int sum=0;
    for(int i=0;i<n;i++)
    {
        sum=sum+n-(lower_bound(a+i+1,a+n,a[i]+x)-a);
        //cout<<x<<" "<<sum<<endl;
    }
    if(sum>num) return 1;
    return 0;
}

int main()
{
    while(~scanf("%d",&n))
    {
        num=n*(n-1)/4;
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+n);
        int l=0,r=a[n-1]-a[0],ans=0;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(ok(mid))
            {
                l=mid+1;
                ans=mid;
            }
            else r=mid-1;
        }
        printf("%d\n",ans);
    }

}