题目大意
给定$n$个数$a_1,a_2,\ldots,a_n$,求这$n$个数两两的差值(共$n*(n-1)/2$个)的中位数。
题目分析
考虑二分中位数$mid$。
计算比$mid$大的二元组有多少个。
计算二元组个数可以采用双指针。
分别找出第一个二元组比$\frac{n(n-1)}{2}$多的$mid$与第一个大于等于$\frac{n(n-1)}{2}$的$mid$,两者起个平均数即为答案。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std;
typedef long long LL;
inline const LL Get_Int() { LL num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; }
const int maxn=200005; LL n,a[maxn];
bool Check(LL mid,bool bj) { LL sum=0; int pos=1; for(int i=1; i<=n; i++) { while(a[i]-a[pos]>mid)pos++; sum+=i-pos; } if(bj) { if(sum*2>n*(n-1)/2)return true; return false; } else { if(sum*2>=n*(n-1)/2)return true; return false; } }
int main() { n=Get_Int(); for(int i=1; i<=n; i++)a[i]=Get_Int(); sort(a+1,a+n+1); LL Left=0,Right=a[n]-a[1]; while(Left<=Right) { LL mid=(Left+Right)>>1; if(Check(mid,1))Right=mid-1; else Left=mid+1; } LL ans1=Left; Left=0,Right=a[n]-a[1]; while(Left<=Right) { LL mid=(Left+Right)>>1; if(Check(mid,0))Right=mid-1; else Left=mid+1; } printf("%lld\n",(Left+ans1)>>1); return 0; }
|