中位数 题解

题意:给定一个序列a,求出这个序列的所有无序数对(一共有n*(n-1)/2个)的差的绝对值的中位数

显然,n^2枚举是会TLE掉的,那么我们换一种思路:二分答案;

对于每个答案,我们可以O(nlogn)验证,比较好想;

然后如果常熟大的话还是会TLE,怎么办呢?

那就是把验证复杂度降为O(n)

其实仔细想一想会发现,验证里的二分出的位置具有单调性,所以双指针扫一遍就可以了;

这种题主要在于细节处理;

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define inc(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
const int MXR=2e5+2;
long long val[MXR];
int n;
long long check(long long mid)
{
	long long res=0;
	int j=1;
	inc(i,1,n){
		while(val[i]-val[j]>=mid) ++j;
		res+=(j-1);		
	}
	return res;
}
signed main()
{	
	cin>>n;
	inc(i,1,n) cin>>val[i];
	sort(val+1,val+1+n);
	long long L=0,R=1e17+1;
	long long goal=n*(n-1)/4;
	while(L<R){
		long long mid=(L+R)/2;
		long long gg=check(mid);
		if(gg>goal){
			L=mid+1;
		}
		else{
			R=mid;
		}
	}
	if((n*(n-1)/2)&1){
		cout<<L-1<<endl;
		//cout<<"this is a test";
		return 0;
	}
	else{
		long long tmp=L-1;
		L=0;R=1e17+1;
		while(L<R){
			long long mid=(L+R)/2;
			long long gg=check(mid);
			//cout<<mid<<"-"<<gg<<endl;
			if(gg>=goal){
				L=mid+1;
			}
			else{
				R=mid;
			}
		}
		//cout<<tmp<<endl;
		cout<<(L-1+tmp)/2<<endl;
	}
}
/*
4
1 4 3 4

3
100 200 400
5
200 400 600 800 1000
*/

  

 

posted @ 2019-10-24 19:42  神之右大臣  阅读(202)  评论(0编辑  收藏  举报