小红的矩阵

[题目链接](https://www.nowcoder.com/practice/c77b7301464f4cfcacc9492a3c999f65)

思路

给一个 的矩阵,第 行第 列的元素为 ,求矩阵中第 小的元素。

暴力行不通

如果 很大,我们没法真的把所有 个元素排序——那可能有 个数。

二分答案

换个角度想:如果我们猜一个值 ,能不能快速算出矩阵里有多少个元素

对于第 行,元素分别是 。其中 的有 个。把所有行加起来就得到总个数:

$$

这个求和只需要 时间。

二分框架

  • 如果 ,说明答案 ,缩小右边界。
  • 如果 ,说明答案 ,抬高左边界。

二分范围 ,总复杂度

样例演示

,矩阵为:

$$

\begin{bmatrix}

1 & 2 & 3 \\

2 & 4 & 6 \\

3 & 6 & 9

\end{bmatrix}

$$

排序后为 ,第 4 小是

二分到 时:第 1 行有 个,第 2 行有 个,第 3 行有 个,总共 ,所以答案不超过 。而 时总共 ,所以答案就是

复杂度

  • 时间复杂度
  • 空间复杂度

代码

#include <bits/stdc++.h>
using namespace std;
int main(){
    long long n, m, k;
    scanf("%lld%lld%lld", &n, &m, &k);
    long long lo = 1, hi = n * m;
    while(lo < hi){
        long long mid = lo + (hi - lo) / 2;
        long long cnt = 0;
        for(long long i = 1; i <= n; i++)
            cnt += min(mid / i, m);
        if(cnt >= k) hi = mid;
        else lo = mid + 1;
    }
    printf("%lld\n", lo);
    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong(), m = sc.nextLong(), k = sc.nextLong();
        long lo = 1, hi = n * m;
        while (lo < hi) {
            long mid = lo + (hi - lo) / 2;
            long cnt = 0;
            for (long i = 1; i <= n; i++)
                cnt += Math.min(mid / i, m);
            if (cnt >= k) hi = mid;
            else lo = mid + 1;
        }
        System.out.println(lo);
    }
}