AtCoder ABC155 D - Pairs(二分 + 二分)

题目链接:https://atcoder.jp/contests/abc155/tasks/abc155_d

题意:给你n个数,问两两相乘的第k大的数是多少。

思路:这一题是个二分的好题。首先考虑二分答案,那我们check函数只需要判断找出这个mid是两两相乘第几大的数。那该如何判断呢?我们可以考虑二分判断,开始我们将所有数按大于等于0和小于0进行分类并排序,之后我们每次在大于等于0,小于0以及大于等于0和小于0之间每次二分查找有多少对乘积比mid小就好啦。这样复杂度就是O( n l o g 2 n n{log}^{2}n )具体详见代码。

AC代码:

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define LL long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

const int maxn = 2e5 + 7;
const LL INF = 1e18;

vector<LL>v1,v2;
LL k;

bool check(LL x) {
    int len1 = v1.size() , len2 = v2.size();
    LL ans = 0;
    /// < * <
    for(int i = 0 ; i < len1 ; i++) {
        LL l = i + 1 , r = len1 - 1;
        LL res = len1;
        while(l <= r) {
            LL mid = (l + r + 1LL) >> 1LL;
            if(v1[i] * v1[mid] <= x) {
                res = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        ans += len1 - res;
    }
    /// > * >
    for(int i = 0 ; i < len2 ; i++) {
        LL l = i + 1 , r = len2 - 1;
        LL res = i;
        while(l <= r) {
            LL mid = (l + r + 1LL) >> 1LL;
            if(v2[i] * v2[mid] <= x) {
                res = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        ans += res - i;
    }
    /// < * >
    for(int i = 0 ; i < len1 ; i++) {
        LL l = 0 , r = len2 - 1;
        LL res = len2;
        while(l <= r) {
            LL mid = (l + r + 1LL) >> 1LL;
            if(v1[i] * v2[mid] <= x) {
                res = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        ans += len2 - res;
    }
    return ans >= k;
}

int main() {
    int n;
    while(~scanf("%d%lld",&n,&k)) {
        v1.clear(),v2.clear();
        for(int i = 1 ; i <= n ; i++) {
            LL x;
            scanf("%lld",&x);
            if(x < 0) v1.push_back(x);
            else v2.push_back(x);
        }

        sort(v1.begin(),v1.end());
        sort(v2.begin(),v2.end());

        LL l = -INF , r = INF;
        LL ans = 0;
        while(l <= r) {
            LL mid = (l + r + 1LL) >> 1LL;
            if(check(mid)) {
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

发布了46 篇原创文章 · 获赞 4 · 访问量 935

猜你喜欢

转载自blog.csdn.net/qq_43423395/article/details/104531774