题解 - 中间

题目描述

慈溪小学编程复赛马上就要到来了,小 A 和小 B 正在做最后的准备工作。
老师最近给小 A 和小 B 考了这样一个问题:有 N 个正整数 a1, a2, …, aN , 对这些正整数任意 2 个做差以后求绝对值。例如,我们对 ai 和 aj 作差,可以得到 |ai − aj|。
显然,这样的差一共有 N(N−1) /2个。
我们令 M = N(N−1)/2 ,输入的 N 保证 M 一定是一个偶数。老师现在想让小 A 和 小 B 求出所有这些绝对值里面从小到大第 M/2小的数。
小 A 和小 B 想了很久,想请你来帮助他们。
注意:在数学中,我们规定一个负数的绝对值就是把它的负号去掉以后的数,例如,| -5| = 5, 而 0 和正数的绝对值还是它本身。

输入

输入的第一行是一个正整数 N,表示数的个数。接下来 N 行,每行一个正整数,表示 ai。

输出

输出所有绝对值中从小到大第 M/2 小的数。

样例

样例输入

4
1
10
2
3

样例输出

2

提示

【样例解释】
样例中,我们总共有 4 个数,求出来的绝对值分别是:|1 − 10| = 9, |1 − 2| = 1, |1 − 3| = 2, |10 − 2| = 8, |10 − 3| = 7, |2 − 3| = 1,从小到大排序以后就是 1,1,2,7,8,9,M 是 3。所以第 M 小的数是 2。
【数据范围】
对于所有的数据,保证 1 ≤ N ≤ 1e5, 1 ≤ ai ≤ 1e9。
请添加图片描述

分析

N 个正整数 a1, a2, …, aN , 对这些正整数任意 2 个做差以后求绝对值。例如,我们对 ai 和 aj 作差,可以得到 |ai − aj|。

差一共有 N(N−1) /2个,求绝对值里从小到大的第 N(N−1) /4 小 的数

要找绝对值里从小到大的第 N(N−1) /4 小的数,可以考虑 二分

直接二分答案,考虑check函数怎么写

假设二分出来的是x,核心是判断比x小于等于的绝对值有多少个(跟m的关系)

先把原数组从小到大排序,则所有的绝对值可以用(l,r)表示出来,其中l < r

枚举i,对于i,a[j] - a[i] 是单调的(j > i)

所以,最后一个 <= a[i] + x 的数 即为 与a[i]的差的绝对值 <= x的最后一个数,

设下标为pos,则 l= i 时对答案的贡献即为 pos - i

最终判断是否 >= m 即可

代码

#pragma GCC optimize(2)
 
#include<bits/stdc++.h>
  
using namespace std;
  
typedef long long LL;
  
const int N = 1e5 + 10;
  
LL n,m;
int a[N];
  
bool check(int x){
    LL cnt = 0;
    for(int i = 0;i < n;i++){
        int pos = upper_bound(a,a + n,a[i] + x) - a - 1;
        cnt += pos - i; 
    }
 
    return cnt >= m;
}
  
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
 
    cin >> n;
    for(int i = 0;i < n;i++) cin >> a[i];
 
    sort(a,a + n);
  
    m = (LL)n * (n - 1) / 2 / 2;
 
    // cout << m << endl;
  
    int l = 0,r = a[n - 1];
  
    while(l < r){
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
        // cout << l << ' '  << r << endl;
    }
  
    cout << l;
  
    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值