Week4 HomeWork 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 的中位数

Sample Input

4
1 3 2 4
3
1 10 2

Sample Output

1
8

算法/思路分析

首先,本题直接记录数组ans再排序找中位数,复杂度O(n2)过高,会TLE。考虑优化,首先对cat进行顺序排序,则可去掉绝对值计算,中位数可根据计算出的ans在数组中的名次判定,名次计算则根据满足cat[j]-cat[i] <= p(j > i)的个数算出p在ans数组中的名次,即cat[j] <= cat[i] + p,循环i,判定满足条件的j的个数。下标j的计算可使用二分优化,记录cat[j] <= cat[i] + p时cat[j]在cat数组中的最终位置final,则从i+1到final都是符合题意的。

注:由于数据较大,cin会TLE,故应使用scanf()获取输入数据

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector> 
using namespace std;
const int maxn = 1e5 + 10;
int cat[maxn];

int n;
int rank1(int p)
{
	int k = 0;
	for(int i = 1; i <= n;i++)
	{
		int s = cat[i] + p;
		int l = i + 1, r = n, tt = -1;
		while(l <= r)
		{
			int mid = (l + r) >> 1; 
			if(cat[mid] <= s)
			{
				tt = mid;
				l = mid + 1;
			}
			else r = mid - 1;
		}
		if(tt == -1) continue;
		else k += tt - i;
	}
	return k;
}

int main()
{
	while(~scanf("%d",&n))
	{
		memset(cat,0,sizeof(cat));
		for(int i = 1; i <= n; i++)
			scanf("%d",&cat[i]);
		sort(cat + 1,cat + n + 1);
		int pp = (n*(n-1)/2+1)/2; //中位数位置
		int l = 0, r = cat[n] - cat[1];
		int re = 0;
		while(l <= r)
		{
			int mid = (l + r) >> 1; 
			if(rank1(mid) < pp) l = mid + 1;
			else 
			{
				re = mid;
				r = mid - 1;
			}
		} 
		
		printf("%d\n",re);
	}
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值