POJ - 3579-Median(二分套娃)

題目鏈接

題意:

給你個數組,求這些數組所有數字之差的絕對值的中位數。

數據範圍:

Xi ≤ 1,000,000,000
3 ≤ N ≤ 1,00,000

思路:

數據很大,所以我們不能暴力hhh,這裏要用到一個二分,首先將數組從小到大排序,這個中位數肯定在1到a[n]之間,所以我們首先在1~a[n]之間進行二分查找,那麼我們如何判斷區間左移還是右移呢?首先我們用小學知識可以計算出差值一共有n*(n-1)/2個,所以如果我們讓原數組中的每個數都加上這個中位數,再和其他數相比較,比他大或比他小的數在所有數中應該有差值的一半也就是n*(n-1)/4個。數字大就左移,數字小就右移。

代碼:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
//#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+7;
int a[N],n,num;
int cmp(int a,int b)
{
    return a<b;
}
bool check(int mid)
{
    int cnt=0;
    for(int i=1;i<=n;i++)//每個數都加上這個數
    {
        cnt+=n-(lower_bound(a+1,a+1+n,mid+a[i])-(a+1));//二分查找有多少個大於他的數
    }
    return cnt>num;//如果cnt偏大說明mid偏小
}
signed main()
{
    while(cin>>n)
    {
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        sort(a+1,a+1+n,cmp);//原數組從大到小排序
        int l=1,r=a[n],res;
        num=n*(n-1)/4;//差值的一半有多少
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid))//判斷該左移還是右移
            {
                res=mid;
                l=mid+1;
            }
            else
            {
                r=mid-1;
            }
        }
        cout<<res<<endl;
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章