zoukankan      html  css  js  c++  java
  • 51Nod1105 第K大的数

    题目链接

    题目描述

    数组A和数组B,里面都有n个整数。
    数组C共有n^2个整数,分别是:
    A[0] * B[0],A[0] * B[1] ...... A[0] * B[n-1]
    A[1] * B[0],A[1] * B[1] ...... A[1] * B[n-1] 
    ......
    A[n - 1] * B[0],A[n - 1] * B[1]  ......  A[n - 1] * B[n - 1]
    是数组A同数组B的组合,求数组C中第K大的数。
    例如:
    A:1 2 3,B:2 3 4。
    A与B组合成的C为
             A[0]  A[1]  A[2]
    B[0]     2      3      4
    B[1]     4      6      8
    B[2]     6      9     12
    共9个数。
    

    输入输出格式

    输入格式:

    第1行:2个数N和K,中间用空格分隔。N为数组的长度,K对应第K大的数。
    第2 - N + 1行:每行2个数,分别是A[i]和B[i]。
    

    输出格式:

    输出第K大的数。
    

    数据范围:

    (2 <= N <= 50000,1 <= K <= 10^9)
    (1 <= A[i],B[i] <= 10^9)
    

    样例

    样例一输入:

    3 2
    1 2
    2 3
    3 4
    

    样例一输出:

    9
    

    思路

    1.二分

    将A数组升序排序,不难发现, $ B_{x} ast A_{i} $ 为升序序列
    那么首先二分第K大的值为h,然后对于序列 $ B_{x} ast A_{i} $ ,二分其中有多少个数小于h
    复杂度 $ Theta left( nlog nlog max left( Aleft[ i ight] ast Bleft[ i ight] ight) ight) $
    还有个小优化
    考虑将A,B都升序排序
    那么序列 $ B_{x} ast A_{i} $ 和 $ A_{x} ast B_{i} $ 都为升序序列
    所以在二分小于h的个数时,第m次二分最大的边界不会超过第m-1次二分的答案
    维护边界变量即可

    #include <algorithm>
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <list>
    #include <map>
    
    #define ll long long
    #define ull unsigned long long
    
    using namespace std;
    
    int n;
    ull a[50050],b[50050];
    ull p,k;
    
    bool check(ull mid) {
        ull sum = 0;
        ull l = 0, r = n, tmp;
        for(int i = 1; i <= n; i++) {
            if(r == 0)break;
            while(l <= r) {
                ull m = (l + r) >> 1;
                if(a[i] * b[m] < mid) {
                    tmp = m;
                    l = m + 1;
                } else r = m - 1;
            }
            sum += tmp;
            l = 0;
        }
        return sum <= p-k;
    }
    
    int main(int argc, char const *argv[])
    {
        scanf("%d%llu",&n,&k);
        p = (ull)n * n;
        for(int i = 1; i <= n; i++) {
            scanf("%llu%llu",&a[i],&b[i]);
        }
        sort(a+1,a+1+n);
        sort(b+1,b+1+n);
        ull l = a[1]*b[1], r = (ull)a[n]*b[n];
        ull ans;
        while(l <= r) {
            ull mid = (l+r) >> 1;
            if(check(mid)) {
                ans = mid;
                l = mid + 1;
            } else r = mid - 1;
        }
        printf("%llu",ans);
        return 0;
    }
    
  • 相关阅读:
    移动Web框架:jQuery Mobile VS Sencha Touch
    2011最具争议性文章:中国网页设计为什么这么烂?
    如何学习嵌入式linux[转]
    嵌入式linux,老手给新手的建议
    开发菜鸟应该知道的十件事
    C#中二进制、八进制、十六进制和十进制之间的相互转化问题
    使用splitter控件 将界面分成可以调整宽度的三个部分
    Mutex 类
    Java 发邮件
    Java Servlet介绍 2
  • 原文地址:https://www.cnblogs.com/ullio/p/9823597.html
Copyright © 2011-2022 走看看