题意:给出a[N],求两个元素差值的中位数(想上取整)
分析:首先,多组输入输出,N<=1e5时间限制1000ms,emmmmm很显然贪心会T 然后,n个元素的差值一共有ans=C(n,2)=n*(n-1)/2中,题目要求第ans/2小的差值,也就是n*(n-1)/4向上取整。好了,接下来想题目要求的是中位数,那我是不是不用求出所有的差值,只要找一个差值作为参考系,看一看这个差值的位置与中位数的位置关系,一步步缩小范围不就好了嘛?听上去像啥子?二分呀!(第一重二分)好嘛,方法找到了,又一个问题来了,怎么确定作为参考系的差值与中位数差值的位置关系呢?这就需要sort了,将a[n]从小到大排一下序,(第二重二分)假设我们找的参考系差值为x,那么遍历a[0]-a[n-1],(假设当前状态下为a[i]),我们找到a[i]后的a[j]>=a[i]+x的第一个值不就是参考系的名次嘛?听上去有没有很熟悉呢,upper_bound是可以实现的啦~
思路:二分的l设为0,r设为最大差值(中位数最大也就等于最大差值),核心代码的check函数就看sum(参考系的实际排名)和num(中位数排名)的关系啦,if(sum>num)说明选的参考系小啦,那么就把l=mid+1,反之则把r=mid-1。
代码:
#include<stdio.h>
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N];
int n,num;
bool check(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);
//得叠加,求的是1-n的所有可能参考系排名的和才是参考系的实际排名
}
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; //最小的差值
int r=a[n-1]-a[0]; //最大的差值
int ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
{
l=mid+1;
ans=mid;
}
else{
r=mid-1;
}
}
printf("%d\n",ans);
}
}