Week4作业C-TT的神秘礼物

1.题意

给定一个 N 个数的数组 cat[i],并用这个数组生成一个新数组 ans[i]。新数组定义为对于任意的 i, j 且 i != j,均有 ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N。试求出这个新数组的中位数,中位数即为排序之后 (len+1)/2 位置对应的数字,’/’ 为下取整。

2.解题思路

  1. 暴力做法,枚举i,j将数列B计算出来,然后根据公式得到其中位数,时间复杂度和空间复杂度均为O(n^2),超时;
  2. 换为名次思路
      给定一个数P,只需通过计算P在数列中的名次即可,在升序序列中如果P的名次比中位数名次小,则P比中位数小,大则P比中位数大,等于则P就是中位数,所以只要满足单调性,就可以二分P
  3. 计算P名次的方法
      将计算B方法去绝对值再移项可得Xj<=Xi+P,i<j,枚举下标i计算满足条件的下标j的个数,同样可二分(已经为第二次二分),即找到第一个大于或等于Xi+P的位置,统计比Xi+P大的名次,遍历i求名次和,如果名次大于B数列长度-中位数名次,l=mid+1,更新范围,否则r=mid-1,最终得到中位数。

3.样例

Input

多组输入,每次输入一个 N,表示有 N 个数,之后输入一个长度为 N 的序列 cat, cat[i] <= 1e9 , 3 <= n <= 1e5>

Output

输出新数组 ans 的中位数

Sample Input

4
1 3 2 4
3
1 10 2

Sample Output

1
8

4.总结

  1. 二分答案,只要是单调的,都可以二分
  2. 该部分不太好理解,还需多做题了解其应用
  3. TLE问题是因为cin太慢了,改为scanf即可
  4. 在寻找第一个大于等于元素的位置时,需要改动一下,即当没有找到时要返回n,因为计算的名次是比中位数大的
int find1(vector<int> &v,int x,int n)
{
	int l=0,r=n-1,ans=-1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(v[mid]>=x)
		{
			ans=mid;
			r=mid-1;
		}
		else if(v[mid]<x) l=mid+1;
	}
	if(ans==-1) ans=n;//此处未找到时返回n
	return ans;
}

5.AC代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int find1(vector<int> &v,int x,int n)
{
	int l=0,r=n-1,ans=-1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(v[mid]>=x)
		{
			ans=mid;
			r=mid-1;
		}
		else if(v[mid]<x) l=mid+1;
	}
	if(ans==-1) ans=n;
	return ans;
}
int main()
{
	int n,a;
	//vector<int>v;
	while(~scanf("%d",&n))
	{
		vector<int>v;
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a);
			v.push_back(a);
		}
		sort(v.begin(),v.end());
		int B=v[v.size()-1]-v[0];
		int l=0;
		int r=B;
		int rm=(n*(n-1)/2+1)/2;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			int rank=0;
			for(int i=0;i<v.size();i++)
			{
				rank=rank+v.size()-find1(v,v[i]+mid,v.size());	
			}
			if(rank>(n*(n-1)/2-rm)) l=mid+1;
			else r=mid-1;
		}
		cout<<l-1<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值