51nod(第K大的数)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1105

很神奇的双层二分……

第一层二分答案 m,看这个数能否做 a[i]*b[j] 的第 k 大的数。判断的时候是计数有多少个a[i]*b[j] > m,先枚举 a[i],再用二分找到与 a[i] 相乘大于 m 的最小的 b[j](数组 a 和数组 b 事先已经从小到大排好序了),那么从 b[j] 开始,后面所有的数和 a[i] 相乘都会大于 m,累加 n-j+1 即为a[i]*b[j]中 大于 m 的个数,用这个数和 k 相比较就能知道这个数是比 第K大的数大了还是小了。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long LL;
const LL maxn = 1e5 + 10;

LL a[maxn];
LL b[maxn];
LL n, k;

LL bin(LL x, LL ai){
    LL l = 0;
    LL r = n - 1;
    LL ret = 0;
    while (l < r){
        LL m = (l + r) >> 1;
        if (b[m] * ai > x){
            r = m;
        }else{
            l = m + 1;
        }
    }
    if (b[r] * ai > x)
        return n - r;
    return n - r - 1;
}

bool check(LL x){
    LL cnt = 0;
    for (LL i=0; i<n; i++){
        cnt += bin(x, a[i]);
    }

    return cnt+1 <= k;
}

LL Bin(){
    LL l = a[0] * b[0];
    LL r = a[n-1] * b[n-1];
    LL ret;
    while (l <= r){
        LL m = (l + r) >> 1;
        if (check(m)){
            r = m - 1;
            ret = m;
        }else{
            l = m + 1;
        }
    }

    return ret;
}

int main()
{
    scanf("%lld%lld", &n, &k);
    for (LL i=0; i<n; i++) scanf("%lld%lld", &a[i], &b[i]);

    sort(a, a+n);
    sort(b, b+n);

    cout << Bin() << endl;
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qust1508060414/article/details/76692849