D. Multiplication Table
https://codeforces.com/problemset/problem/448/D
题意:n*m矩阵,对应位置的数值是行列下标相乘,求排序后第k个元素数值。
思路:元素值最大是n * m, 最小是1,在这个范围内2分,统计出所有比当前数值x(二分值)小的数的数量cnt,如果cnt<k,那么x有可能是第k个值,要将二分的左边界右移。
总结:cnt < k 是个比较难理解的点。cnt < k 说明比x小的数不到k个,那么x也有可能是第cnt + 1~k - 1个数,所以需要将左边界右移。
还有个难理解的点是如何统计出比x小的数的数量。一开始想的是按斜线遍历,但是很复杂感觉无法实现。正解应该是按行遍历,因为x已知,行号i已知,则可以求出最大j,j值就是该行中小于x的值的数量(如果j>m,那么j=m)
感觉也算是经典模板题了,矩阵上第k大二分
void solve(){
long long n, m;
cin >> n >> m;
long long k;
cin >> k;
auto valid = [&](long long x){
long long cnt = 0;
for (int i = 1; i <= n; ++i){
cnt += min(m, (x - 1) / i);
}
return cnt < k;
};
long long l = 1, r = n * m;
while (l < r){
long long mid = (l + r + 1) >> 1;
if (valid(mid)){
l = mid;
}
else{
r = mid - 1;
}
}
cout << l << endl;
}