Description:
给定n个数,求所以两两之间的差值的中位数。
Data range:
2 ≤ n ≤ 50000 , 2|a i
Solution:
ps: sm(small)是比mid小的差值的个数 bg(big)是大的 cnt是差值的总个数
这些差值的总数是n*(n-1)/2个 从数据范围来看 是没有办法存起来的
我们可以二分这个中位数
对于我们二分的可能答案 可以求出所有的中位数中比它小的和大的数的个数
根据这个就可以判断二分的值是偏小还是偏大啦(具体见code很好理解)
但是当差值的总数是偶数时 中位数为中间两个数的平均数
发现对于一个二分的一个值 sm==bg&&sm+bg==cnt时一定是出现的上面的那种情况
这时我们需要找到中间的两个数 所以就有了第二次和第三次二分
中间的两个数分别是sm<bg的最大值和sm>bg的最小值
attention: lower_bound()是找到第一个大于等于x的数的位置
upper_bound()是找到第一个大于x的数的位置
CODE
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #define R register 6 #define go(i,a,b) for(R int i=a;i<=b;++i) 7 #define ll long long 8 #define db double 9 #define il inline 10 #define M 50001 11 #define inf 2100000000 12 using namespace std; 13 il int rd() 14 { 15 int x=0,y=1;;char c=getchar(); 16 while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();} 17 while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();} 18 return x*y; 19 } 20 int n,cnt,x,y,a[M]; 21 ll bg,sm; 22 il void calc(int x) 23 { 24 go(i,1,n) 25 { 26 sm+=lower_bound(a+i+1,a+n+1,a[i]+x)-a-i-1; 27 bg+=n-(upper_bound(a+i+1,a+n+1,a[i]+x)-a-1); 28 } 29 } 30 int main() 31 { 32 freopen("1.in","r",stdin); 33 freopen("1.out","w",stdout); 34 n=rd();cnt=(ll)n*(n-1)/2; 35 go(i,1,n) a[i]=rd(); 36 sort(a+1,a+n+1); 37 38 int l=0,r=a[n]-a[1]+1,mid; 39 while(l<=r) 40 { 41 mid=(l+r)>>1; 42 sm=0,bg=0;calc(mid); 43 if(bg==sm) 44 { 45 if(bg+sm==cnt) break; 46 else {printf("%d",mid);return 0;} 47 } 48 if((abs(bg-sm)<(cnt-bg-sm))||(abs(bg-sm)==(cnt-bg-sm)&&(cnt%2))){printf("%d",mid);return 0;} 49 if(bg>sm) l=mid+1; 50 else r=mid-1; 51 } 52 53 l=0,r=a[n]-a[1]+1; 54 while(l<=r) 55 { 56 mid=(l+r)>>1; 57 sm=0;bg=0;calc(mid); 58 if(sm<bg) x=mid,l=mid+1; 59 else r=mid-1; 60 } 61 l=0,r=a[n]-a[1]+1; 62 while(l<=r) 63 { 64 mid=(l+r)>>1; 65 sm=0;bg=0;calc(mid); 66 if(sm>bg) y=mid,r=mid-1; 67 else l=mid+1; 68 } 69 70 printf("%d",(x+y)/2); 71 return 0; 72 }