问题描述:
TT 是一位重度爱猫人士,每日沉溺于 B 站上的猫咪频道。
有一天,TT 的好友 ZJM 决定交给 TT 一个难题,如果 TT 能够解决这个难题,ZJM 就会买一只可爱猫咪送给 TT。
任务内容是,给定一个 N 个数的数组 cat[i],并用这个数组生成一个新数组 ans[i]。新数组定义为对于任意的 i, j 且 i != j,均有 ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N。试求出这个新数组的中位数,中位数即为排序之后 (len+1)/2 位置对应的数字,’/’ 为下取整。
TT 非常想得到那只可爱的猫咪,你能帮帮他吗?
输入输出:
Input:多组输入,每次输入一个 N,表示有 N 个数,之后输入一个长度为 N 的序列 cat, cat[i] <= 1e9 , 3 <= n <= 1e5
output:输出新数组 ans 的中位数
解题思路:
给出一个数组,然后根据这个数组构造一个新数组,求这个新数组的中位数,这里利用了二分答案的思想,即最开始中位数会有一个区间,中位数一定位于这个区间内,二分到一个可能答案jiashe,求该答案的名次,如果该名次比中位数的名次小,就在jiashe+1到r这个区间找,反之,在l到jiashe区间找,一直利用二分过程,直到low>high,循环结束此时的jiashe就是最终要求的中位数。
首先看,怎么求一个数的名次,根据新数组的构建方式ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N,可知,要知道这个数大于等于ans[]数组的多少数,对数组cat进行排序,问题转化为即jiashe≥cat[j] - cat[i](1 <= i < j <= N) ,可以通过枚举i,二分j,即cat[j]<=cat[i]+jiashe,找到数组中最后一个<=cat[i]+jiashe的索引即可。为了避免不必要的搜索,优化剪枝,对于每一个jiashe,从数组中某个i开始,j从i+1到n-1会一直满足条件,所以先找到这个临界值,a[n-1]-a[i]<=jiashe,a[i]>=a[n-1]-jiashe,找到第一个大于该值的索引。问题转化为从i从0到这个临界值的枚举,然后二分搜索求j。
实验代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[100100];
int BinarySearch(int goal,int left,int right)
{
int l=left,r=right;
int mid,ans=left-1;
while(l<=r)
{
mid=(r+l)/2;
if(a[mid]>goal)
{
r=mid-1;
}
else
{
ans=mid;
l=mid+1;
}
}
return (ans-left+1);
}
int BinarySearch_bigger(int goal,int left,int right)
{
int l=left,r=right;
int mid,ans=-1;
while(l<=r)
{
mid=(r+l)/2;
if(a[mid]<goal)
{
l=mid+1;
}
else
{
ans=mid;
r=mid-1;
}
}
return ans;
}
int getAns(int n)
{
long long int len=n*(n-1)/2;
long long int ansless=(len+1)/2 ;
int low=0,high=a[n-1]-a[0];
int jiashe;
while(low<=high)
{
jiashe=(high+low)/2; //二分答案
if(low==high)
return jiashe;
long long int mc=0;
int end;
if((end=BinarySearch_bigger(a[n-1]-jiashe,0,n-1))!=-1) //找临界值
mc+=(n-end)*(n-end-1)/2;
else end=n-1;
for(int i=0;i<end;i++)
{
if(a[i+1]-a[i]<=jiashe)
mc+=BinarySearch(jiashe+a[i],i+1,n-1);
}
if(mc>=ansless)
high=jiashe;
else if(mc<ansless)
low=jiashe+1;
}
}
int main(void)
{
int n;
while(scanf("%d",&n))
{//接下来要输入n个数
for(int i=0;i<n;i++)
scanf("%d",&a[i]); //输入数据
sort(a,a+n);
printf("%d\n",getAns(n));
}
return 0;
}