week4 C - 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 的中位数

解题思路:

给出一个数组,然后根据这个数组构造一个新数组,求这个新数组的中位数,这里利用了二分答案的思想,即最开始中位数会有一个区间,中位数一定位于这个区间内,二分到一个可能答案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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值