题目链接
题目描述
小红有一个 的矩阵,矩阵第
行第
列的元素为
,小红想知道矩阵中第
小的元素是多少。
输入:
- 一行三个整数
、
、
,分别表示矩阵的行数、列数和要找的第k小的数
输出:
- 输出一个整数表示答案
解题思路
这是一个二分查找问题,可以通过以下步骤解决:
-
关键发现:
- 矩阵中第 i 行第 j 列的元素是 i×j
- 矩阵是行列都有序的(每行每列都递增)
- 不需要实际构造矩阵,只需要能够计算有多少个数小于等于某个值
-
解题策略:
- 使用二分查找猜测第k小的数
- 对于每个猜测的数,计算矩阵中有多少个数小于等于它
- 根据计数结果调整二分查找的范围
-
具体步骤:
- 确定二分查找的范围(1到n×m)
- 对于每个中间值,计算矩阵中小于等于它的数的个数
- 根据计数结果调整二分范围
- 最终找到第k小的数
代码
#include <bits/stdc++.h>
using namespace std;
// 计算矩阵中小于等于mid的数的个数
long long count(long long n, long long m, long long mid) {
long long cnt = 0;
for(long long i = 1; i <= n; i++) {
// 对于每一行,计算有多少个数小于等于mid
cnt += min(m, mid / i);
if(cnt > 1e18) return cnt; // 防止溢出
}
return cnt;
}
int main() {
long long n, m, k;
cin >> n >> m >> k;
long long left = 1, right = n * m + 1; // 增大右边界
while(left < right) {
long long mid = left + (right - left) / 2;
if(count(n, m, mid) >= k) {
right = mid;
} else {
left = mid + 1;
}
}
cout << left << endl;
return 0;
}
import java.util.*;
public class Main {
// 计算矩阵中小于等于mid的数的个数
static long count(long n, long m, long mid) {
long cnt = 0;
for(long i = 1; i <= n; i++) {
// 对于每一行,计算有多少个数小于等于mid
cnt += Math.min(m, mid / i);
if(cnt > (long)1e18) return cnt; // 防止溢出
}
return cnt;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
long m = sc.nextLong();
long k = sc.nextLong();
long left = 1, right = n * m + 1; // 增大右边界
while(left < right) {
long mid = left + (right - left) / 2;
if(count(n, m, mid) >= k) {
right = mid;
} else {
left = mid + 1;
}
}
System.out.println(left);
}
}
def count(n, m, mid):
# 计算矩阵中小于等于mid的数的个数
cnt = 0
for i in range(1, n + 1):
# 对于每一行,计算有多少个数小于等于mid
cnt += min(m, mid // i)
if cnt > 10**18: # 防止溢出
return cnt
return cnt
n, m, k = map(int, input().split())
left, right = 1, n * m + 1 # 增大右边界
while left < right:
mid = left + (right - left) // 2
if count(n, m, mid) >= k:
right = mid
else:
left = mid + 1
print(left)
算法及复杂度
- 算法:二分查找
- 时间复杂度:
- 二分查找需要
次,每次需要
时间计数
- 空间复杂度:
- 只需要常数空间
注意:
- 不需要实际构造矩阵,只需要能够计算小于等于某个数的元素个数
- 所有变量都使用 long long/long 类型避免整数溢出
- 在计数时需要处理溢出情况
- 二分查找的右边界需要足够大