10.26T1 二分

#3856 中位数

描述

给定n个数 a1,a2,...,an,求这n个数两两的差值(共n*(n-1)/2个)的中位数。

输入

第一行一个正整数n,表示数的个数。

接下来一行n个正整数,分别为a1,a2,...,an。

输出

输出仅一行一个数表示差值的中位数

样例输入[复制]
3
4 2 6
样例输出[复制]
2
提示

【样例解释】

  差值分别为 2,2,4,中位数为 2。

【数据规模和约定】

  对于30%的数据,n≤500。

  对于70%的数据,n≤5000。

  对于100%的数据,2≤n≤200000,2|ai。

二分中位数的大小,我们可以用一个单调队列线性查出对于一个数来说差小于这个值的数字个数,求和比较一下就可以了

当然也可以二分右端点,多了一个log

注意此题如果是偶数个差会导致中位数有概率是奇数,所以我们对此要二分两次,第一次二分位置强行在n/2的地方,第二次是n/2+1,两者加起来求值就可以了

我当然挂了25分啦

我写了一年错误的二分

code:

 1 #include<algorithm>
 2 #include<cmath>
 3 #include<ctime>
 4 #include<cstdio>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<iostream>
 8 #include<queue>
 9 #include<vector>
10 using namespace std;
11 typedef long long ll;
12 const int N=200001;
13 ll n;
14 ll a[N];
15 ll smaller(ll mid)
16 {
17     ll L=1,R=1,ans=0;
18     for(;R<=n;R++)
19     {
20         while(a[R]-a[L]>mid) L++;
21         ans+=R-L;
22     }
23     return ans;
24 }
25 ll bsearch(ll pos)
26 {
27     ll L=0,R=a[n]-a[1];
28     while(L<=R)
29     {
30         ll mid=(L+R)>>1;
31         if(smaller(mid)<pos) L=mid+1;
32         else R=mid-1;
33     }
34     return L;
35 }
36 int main()
37 {
38     scanf("%lld",&n);
39     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
40     sort(a+1,a+1+n);
41     ll num=(n-1)*n/2;
42     if(num%2) cout<<bsearch((num)/2);
43     else cout<<(bsearch(num/2)+bsearch(num/2+1))/2;
44     return 0;
45 }

over

原文地址:https://www.cnblogs.com/saionjisekai/p/9858450.html