week4作业——C二分

主要思路:

由于本题的n最大为1e5,所以仅仅求出ans数列已经达到了O(n2)的复杂度,所以需要其他的思路;

二分中位数

考虑我们求的中位数的范围:大于等于零,这是因为ans的每个元素为abs(cat[i] - cat[j]);小于等于cat数列最大值与最小值之差,这是因为ans的每个元素由cat生成。并且名次是单调的,所以在这个范围内我们可以二分求出中位数,使用的一个评判标准便是名次与(len(ans)+1)/2的大小关系

名次的计算

所以,现在的问题变成了求一个数P的名次,即求出在cat中有多少cati和catj满足|cati - catj| <=P 这样的数对。这里去掉绝对值的方法,可将cat数组提前排序就可以保证cati <= catj,进而满足的关系可变形为cati +P >= catj,于是,我们对于每一个cati 我们去二分找到符合条件的所有catj,进而求出名次

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

A Possible Solution

#include<stdio.h>
#include<algorithm>
using namespace std;

int n,arr[100005];

int getRank(int target){
	if(target==0)
		return 0;
	int res=0;
	for(int i=0;i<n;i++){
		int l=i+1,r=n-1,mid,ans=0;
		while(l<=r){
			mid=(l+r)>>1;
			if(arr[mid]>arr[i]+target)r=mid-1;
			else{
				ans=mid;
				l=mid+1;
			}
		}
		if(ans)
			res+=(ans-i);
	}
	return res;
}

int main(){
	while(~scanf("%d",&n)){
		for(int i=0;i<n;i++){
			scanf("%d",arr+i);
		}
		sort(arr,arr+n);
//		for(int i=0;i<n;i++)printf("%d ",arr[i]);
		int l=0,r=arr[n-1]-arr[0],target=(2+n*(n-1))/4,rank_mid,mid,ans;
//		for(int i=l;i<=r;i++){
//			printf("%d  ",getRank(i));
//		}printf("\n");
		while(l<r){
			mid=(l+r)>>1;
			rank_mid=getRank(mid);
			if(rank_mid>=target)
				r=mid;
			else
				l=mid+1;
			/*if(rank_mid>target)r=mid-1;
			else if(rank_mid<target)l=mid+1;
			else{
				ans=mid;
				r=mid-1;
			}*/
		}
		printf("%d\n",l);
	}
	return 0;
} 
发布了26 篇原创文章 · 获赞 0 · 访问量 494

猜你喜欢

转载自blog.csdn.net/weixin_43669888/article/details/104981674
今日推荐