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;
}

猜你喜欢

转载自blog.csdn.net/ACkingdom/article/details/106599664