C - Multiplication Table CodeForces - 448D
题目:
Problem Description
Bizon the Champion isn’t just charming, he also is very smart.
While some of us were learning the multiplication table, Bizon the Champion had fun in his own manner. Bizon the Champion painted an n × m multiplication table, where the element on the intersection of the i-th row and j-th column equals i·j (the rows and columns of the table are numbered starting from 1). Then he was asked: what number in the table is the k-th largest number? Bizon the Champion always answered correctly and immediately. Can you repeat his success?
Consider the given multiplication table. If you write out all n·m numbers from the table in the non-decreasing order, then the k-th number you write out is called the k-th largest number.
Input
The single line contains integers n, m and k (1 ≤ n, m ≤ 5·105; 1 ≤ k ≤ n·m).
Output
Print the k-th largest number in a n × m multiplication table.
Examples
Input
2 2 2
Output
2
Input
2 3 4
Output
3
Input
1 10 5
Output
5
Note
A 2 × 3 multiplication table looks like this:
1 2 3
2 4 6
题意
第i行 第j列的数字等于 ij,求这 nm 个数字中的第 k 大的数字
题解
注意 n*m 会爆 int
- 暴力排序
- 找规律二分:
设第 k 个数字是 wsy
第二行是第一行的2倍,第三行是第一行的3倍。。。
因此,第 i 行比 wsy 小的数有 wsy / i 个,对 wsy 在区间 0~k内进行查找(因为数字重复出现,所以第 k 个数字一定比 k 小)
复杂度分析
- 暴力排序 > O(nm)= 2.51e11,超时
- 找规律二分 O(n *log k) = O(n *log m) == 1e6 ~ 1e7
算法
二分查找
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n, m, k, l, r, mid;
// find() 用来查比 mid 大的数字有多少个
ll find(ll wsy) {
ll sum = 0;
for(int i = 1; i <= n; i++) {
sum += min(m, wsy/i);
}
return sum;
}
int main() {
freopen("test.in", "r", stdin);
while(cin >> n >> m >> k) {
l = 0, r = k;
while(l <= r) {
mid = l + (r-l)/2;
if(find(mid) > k) r = mid - 1;
// 如果 >= mid 的数字比 k 大,则 mid 大了
else l = mid + 1;
if(find(mid) == k) {
l = mid;
break;
}
}
cout << l << endl;
}
return 0;
}