• 【每日一题】ABC155D - Pairs | 二分双指针 | 简单


    题目内容

    原题链接

    给定一个长度为 n n n 的整数数组 a a a

    选择两个不同的下标 i i i j j j ,乘积为 a i × a j a_i\times a_j ai×aj

    问在 n × ( n − 1 ) 2 \frac{n\times (n-1)}{2} 2n×(n1) 种不同的元素对中,第 k k k 小乘积是多少。

    数据范围

    • 2 ≤ n ≤ 2 × 1 0 5 2\leq n\leq 2\times 10^5 2n2×105
    • 1 ≤ k ≤ n × ( n − 1 ) 2 1\leq k\leq \frac{n\times (n-1)}{2} 1k2n×(n1)
    • − 1 0 9 ≤ a i ≤ 1 0 9 -10^9\leq a_i\leq 10^9 109ai109

    题解

    二分第 k k k 小乘积 m i d mid mid

    然后 c h e c k check check 是否有至少 k k k 个元素对的乘积小于等于 m i d mid mid

    c h e c k check check 中使用双指针来降低时间复杂度,如果在 c h e c k check check 中也使用二分,就得多一个 O ( log ⁡ n ) O(\log n) O(logn) 的复杂度。

    时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)

    代码

    #include 
    using namespace std;
    
    typedef long long ll;
    
    int main()
    {
        int n;
        cin >> n;
    
        ll k;
        cin >> k;
    
        vector<int> pos, neg;
        ll zero = 0;
        for (int i = 0; i < n; ++i) {
            int x; cin >> x;
            if (x == 0) zero += 1;
            else if (x > 0) pos.push_back(x);
            else neg.push_back(x);
        }
    
        int nn = int(neg.size());
        int np = int(pos.size());
        zero = zero * (zero - 1) / 2 + zero * (nn + np);
    
        sort(pos.begin(), pos.end());
        sort(neg.begin(), neg.end(), greater<>());
    
        ll mul_neg = 1ll * nn * np;
        if (k <= mul_neg) {
            auto check = [&](ll mid) {
                // mul 为负数小于等于 mid 的
                // 考虑正数对应的所有负数即可,这块可以双指针
                // 枚举每个正数,找到对应的一个最大的负数,满足两数之积小于等于 mid
    
                ll cnt = k;
                for (int i = np - 1, j = 0; i >= 0; --i) {
                    while (j < nn && 1ll * pos[i] * neg[j] > mid) j += 1;
                    cnt -= (nn - j);
                }
    
                return cnt <= 0;
            };
    
            ll l = -1e18, r = -1;
            while (l < r) {
                ll mid = (l + r) >> 1;
                if (check(mid)) r = mid;
                else l = mid + 1;
            }
    
            cout << l << "\n";
        } else if (k <= mul_neg + zero) {
            cout << "0\n";
        } else {
            auto check = [&](ll mid) {
                // mul 为正数小于等于 mid 的
    
                ll cnt = k - mul_neg - zero;
                // 正数 * 正数
                for (int i = 0, j = np - 1; i < j; ++i) {
                    while (j >= 0 && 1ll * pos[i] * pos[j] > mid) j -= 1;
                    if (i < j) cnt -= j - i;
                }
    
                if (cnt <= 0) return true;
    
                // 负数 * 负数
                for (int i = 0, j = nn - 1; i < nn; ++i) {
                    while (j >= 0 && 1ll * neg[i] * neg[j] > mid) j -= 1;
                    if (i < j) cnt -= j - i;
                }
    
                return cnt <= 0;
            };
            ll l = 1, r = 1e18;
            while (l < r) {
                ll mid = (l + r) >> 1;
                if (check(mid)) r = mid;
                else l = mid + 1;
            }
            cout << l << "\n";
        }
    
        return 0;
    }
    
    • 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
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
  • 相关阅读:
    MySql
    DT灯光基础(辉光 雾 阴影 渲染选项)
    理解C#中对象的浅拷贝和深拷贝
    抽象轻松的java——简单的购物车系统
    玩转数据可视化之R语言ggplot2:(十一)坐标轴和刻度线设置2
    Photoshop-图层相关概念-LayerComp-Layers-移动旋转复制图层-复合图层
    高压功率放大器在超声悬浮中的应用研究
    Image (mathematics)
    问:毁掉一个人,有多容易?答:年龄到了就可以
    《算法导论》第11章-散列表 11.1-直接寻址表 11.2 散列表
  • 原文地址:https://blog.csdn.net/weixin_43900869/article/details/132871367