TT 的神秘礼物
题目:
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 的中位数
Example:
Input:
4
1 3 2 4
3
1 10 2
Output:
1
8
我的思路:
根据题意,我们要对于一个数组中,两个数的差的绝对值,然后计算绝对值数列的中位数。可以通过将数组从小到大排序,然后计算 后面的数-前面的数 ,这样可以去除绝对值。然后可以通过二分法进行优化。选取最大差值(即排序后数组的最后一个数减去第一个数)最为max,0为min,进行二分,计算mid的排名。因为,我们可以知道最后中位数的排名,所以只要对比排名就可以了。计算排名也可以用到二分法,即计算小于这个数的差值的个数(即计算差值比其小的数对对数就可以了)。
我的总结:
为了时间复杂度考虑,要尽量使用scanf,printf。(cin,cout一直超时,换成scanf,printf直接AC)
我的代码:
#include<cstdio>
#include<algorithm>
using namespace std;
long long cat[100000],N;
/*int count_rank(int P)
{
int rank=0;
for(int i=0;i<N;i++)
{
int l=i+1,r=N-1,ans=i,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(cat[mid]-cat[i]<P) ans=mid,l=mid+1;
else r=mid-1;
}
rank=rank+(ans-i);
}
return rank;
}*/
int count_rank(int P)
{
int rank=0;
for (int i=0;i<N;i++)
{
int l=i+1,r=N-1,ans=i;
for(int q=0;q<15;q++)
{
int mid=(l+r)>>1;
if(cat[mid]-cat[i]<=P)
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
rank+=ans-i;
}
return rank;
}
long long bifind()
{
long long l=0 , r=cat[N-1]-cat[0],mid_rank=N*(N-1)/4+N*(N-1)/2%2,mid,ans;
for(int i=0;i<20;i++)
{ mid=(l+r)>>1;
//cout<<count_rank(mid)<<endl;
if(count_rank(mid)>=mid_rank) {
r=mid;
}
else l=mid;
}
return r;
}
int main()
{
while(~scanf("%d",&N))
{
for (int i=0;i<N;i++)
{
scanf("%lld",&cat[i]);
}
sort(cat,cat+N);
printf("%lld\n",bifind());
}
return 0;
}