zoukankan      html  css  js  c++  java
  • 题解【CJOJ2608】[JZOJ 100043]第k小数

    Description

    有两个非负整数数列,元素个数分别为N和M。从两个数列中分别任取一个数相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少。

    时间限制为20ms

    Input

    输入文件包含三行。
    第一行为三个正整数N,M和K。
    第二行为N个整数,表示第一个数列。
    第三行为M个整数,表述第二个数列。

    Output

    输出文件包含一行,一个正整数表示第K小数。

    Sample Input

    Sample1:
    2 3 4
    1 2
    2 1 3

    Sample2:
    5 5 18
    7 2 3 5 8
    3 1 3 2 5

    Sample Output

    Sample1:
    3

    Sample2:
    16

    Hint

    Pic

    Source

    二分 /单调性
    source JZOJ 100043
    鸣谢陈思宇制作数据!

    Solution

    我们先对于a、b数组分别排一次序,使这两个数组都具有单调性。

    考虑二分答案。

    假设现在二分到了mid,那么前k小的数都应满足a[i]*b[j]≤mid。

    现在,我们要枚举i和j使得mid满足上述条件。

    考虑如何快速地算出j。

    由于a、b数组都具有了单调性,因此我们得到的j也是单调递减的,就可以利用单调性轻松求出j。

    所以我们得出的算法的时间复杂度为O(N*log(最大的数)),轻松通过!

    Code

     1 #include <bits/stdc++.h>
     2 #define int long long
     3 
     4 using namespace std;
     5 
     6 inline int read()//快读
     7 {
     8     int f = 1, x = 0;
     9     char c = getchar();
    10 
    11     while (c < '0' || c > '9')
    12     {
    13         if (c == '-')
    14             f = -1;
    15         c = getchar();
    16     }
    17 
    18     while (c >= '0' && c <= '9')
    19     {
    20         x = x * 10 + c - '0';
    21         c = getchar();
    22     }
    23 
    24     return f * x;
    25 }
    26 
    27 int n, m, k, a[20005], b[20005];
    28 
    29 signed main()
    30 {
    31     n = read(), m = read(), k = read();
    32 
    33     for (register int i = 1; i <= n; i++)
    34     {
    35         a[i] = read();
    36     }
    37 
    38     for (register int i = 1; i <= m; i++)
    39     {
    40         b[i] = read();
    41     }
    42 
    43     sort(a + 1, a + 1 + n);//排序
    44     sort(b + 1, b + 1 + m);
    45 
    46     int l = 1, r = a[n] * b[m];
    47 
    48     while (l < r)//二分
    49     {
    50         int mid = (l + r) >> 1, sum = 0;
    51 
    52         for (register int i = 1, j = m; i <= n; i++, sum = sum + j)//枚举i,并且计算满足条件的个数
    53         {
    54             while (a[i] * b[j] > mid)//如果满足条件
    55             {
    56                 --j;//每次更新j
    57             }
    58         }
    59 
    60         if (sum >= k)//如果答案比k大
    61         {
    62             r = mid;//缩小最大值范围
    63         }
    64         else
    65         {
    66             l = mid + 1;//否则更新最小值
    67         }
    68     }
    69 
    70     printf("%lld", l);//输出符合条件的答案个数
    71 
    72     return 0;//结束
    73 }
  • 相关阅读:
    增加新分类daily——“每天学了啥?”
    gcc选项中的编译过程
    一个带路径复制的perl脚本
    git
    mysql explain 详解
    CentOS Python2.4升级到Python2.7
    mongoDb查询
    linux php 扩展
    php-redis 扩展安装
    redis Linux的安装方法
  • 原文地址:https://www.cnblogs.com/xsl19/p/10520045.html
Copyright © 2011-2022 走看看