Topics
In this problem, we are given an multiplication table where the entry at position is . Find the -th number when all numbers are sorted in non-decreasing order.
Idea
The smallest value in the table is . The largest value is . Thus, our search space for the -th number lies within the range .
We can use binary search, but we need a function that, for a given candidate value , tells us how many numbers in the multiplication table are . Let’s consider row . The numbers in row are . The count of numbers in row that are is given by:
Summing this count over all rows from to gives us the total count of numbers in the table that are :
Since is monotonic, and we need to find the smallest for which , we can use the binary search boolean array framework. Evaluating check(x) = (count(x) >= k)
for every value of in our search space would generate a boolean array: 0,0,...,0,1,1,...,1
. Our goal is to find the transition point, i.e. the first 1
.
Note that this works correctly for duplicates as seen for the example:
Example
We have
n=2, m=3, table=[1, 2, 2, 3, 4, 6]
and we want the -nd element which’s2
. Observe that when , we have and for , . Thus,check(1)
isfalse
whilecheck(2)
istrue
and will be returned as answer since it’s the transition point.
Warning
Even though our search space includes elements that aren’t in the table (e.g. 5 in this case), this transition point must occur at one of the actual table values , ensuring the correctness of the solution.
Time Complexity:
Space Complexity:
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
bool check(ll mid, ll n, ll m, ll k) {
ll cnt = 0;
for (ll i = 1; i <= n; i++) {
// Count how many numbers in row i are <= mid
// which is min(mid/i, m)
cnt += min(mid / i, m);
}
return (cnt >= k);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n, m, k;
cin >> n >> m >> k;
ll lo = 1;
ll hi = n * m;
ll ans = hi;
// Binary search for the k-th smallest
while (lo <= hi) {
ll mid = (lo + hi) / 2;
if (check(mid, n, m, k)) {
ans = mid;
hi = mid - 1;
} else {
lo = mid + 1;
}
}
cout << ans << "\n";
return 0;
}
Related
- https://cses.fi/alon/task/2422/
- can be solved by putting and (middle element).