2014-03-08 09:47:04Morris

[其他題目][二分答案] 差值中位數

Description

有 n 個整數,則任兩個數字有一個差值 (取絕對值)。
因此會有 C(n, 2) 個差值,求這 C(n, 2) 個整數的中位數。

Input Format

第一行有一個正整數 T,代表有幾組測試資料。

每組測資第一行有一個正整數 n (n < 100,000),
接著第二行有 n 個正整數 A[i] (0 < A[i] < 1,000,000,000)。

Output Format

每筆測資請輸出一行,包含一個整數,代表差距中的中位數。
若 C(n, 2) 是偶數,則輸出較大的那一個。

Sample Input

2
4
1 3 5 8
3
1 2 3

Sample Output

4
1

題目解法:

先對輸入做排序,然後二分答案(最後的中位數)檢查這個整數,坐落於排名第幾,試圖推到中位數的位置。

檢查的方式 =>
對於每一個數字 x,找到 upper_bound(x+guess_number) 的位置,找到與 x 可以湊出差值小於等於 guess_number 的個數。

效率 O(n log^2 n )


#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#define oo 1000000000
using namespace std;
int A[100001], flag;
int cmp(const void *i, const void *j) {
    return *(int *)i - *(int *)j;
}
int Find_Median(long long n) {
    long long Gap = n*(n-1)/2, tmp1, tmp2;
    int l = 0, m, r = oo, i, flag = 0;
    int idx;
    Gap = Gap/2 + 1;
    do {
        m = (l + r)/2, tmp1 = 0, tmp2 = 0, flag = 0;
        idx = 0;
        for(i = 0; i < n; i++) {
            while(idx < n && A[idx]-A[i] <= m)    {
                if(A[idx]-A[i] == m)    flag = 1;
                idx++;
            }
            tmp1 += idx - i - 1;
        }
        if(flag) {
            idx = 0;
            for(i = 0; i < n; i++) {
                while(idx < n && A[idx]-A[i] < m)
                    idx++;
                tmp2 += idx - i - 1;
            }
        }
        if(tmp1 >= Gap && tmp2 < Gap && flag != 0)    return m;
        if(tmp1 < Gap)    l = m+1;
        else    r = m-1;
    } while(l <= r);
}
int main() {
    int i, j, n, k = 0;
    int testcase;
    scanf("%d", &testcase);
    while(testcase--) {
        scanf("%d", &n);
        for(i = 0; i < n; i++)
            scanf("%d", &A[i]);
        sort(A, A+n);
        printf("%d\n", Find_Median(n));
    }
    return 0;
}