题目链接
题意:
给你个数组,求这些数组所有数字之差的绝对值的中位数。
数据范围:
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;
}