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 非常想得到那只可爱的猫咪,你能帮帮他吗?
多组输入,每次输入一个 N,表示有 N 个数,之后输入一个长度为 N 的序列 cat, cat[i] <= 1e9 , 3 <= n <= 1e5
输出新数组 ans 的中位数
4
1 3 2 4
3
1 10 2
1
8
1、通过暴力枚举计算数列ans[]的时间复杂度为O( N 2 N^2 N2),无法接受
2、本题通过二分答案解决。
3、计算Pmid在ans数组中位次的方法:
4、输入数据请用scanf,用cin会超时
#include
#include
#include
#include
using namespace std;
int n;
vector<int> cat;
//找到<=x的最后一个位置
int findr(int x){
int l=0,r=cat.size()-1,ans=-1;
while(l<=r){
int mid=(l+r)/2;
if(cat[mid]<=x){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
return ans;
}
int main(){
while(scanf("%d",&n)!=EOF){
cat.clear();
for(int i=0;i<n;i++){
int temp=0;scanf("%d",&temp);
cat.push_back(temp);
}
//从小到大排列去绝对值
sort(cat.begin(),cat.end());
//n个元素,数列x中元素的个数为n(n-1)/2 ,位数排第【(n(n-1)+2)/4】
int targetrank=(n*(n-1)+2)/4;
// cout<<"目标名次是"<
//p的最大值、最小值
int pr=cat.back()-cat.front(),pl=0,ans=-1;
while(pl<=pr){
int pmid=(pl+pr)/2,ppos=0;
//固定下标i然后计算满足条件的下标j的个数(即为p的名次)
for(int i=0;i<cat.size();i++){
int b=cat[i]+pmid;
int pos=findr(b);
if(pos!=-1){
ppos+=pos-i;
}
}
if(ppos>=targetrank){
ans=pmid;
pr=pmid-1;
}
else {
pl=pmid+1;
}
}
cout<<ans<<endl;
}
}