题目大意:
给你三个数n,m,k
然后会根据n,m生成数列
1×1,1×2,······,1×m
2×1,2×2,······,2×m
···
n×1,n×2,······,n×m
问你将这些数字中第k大的数字是多少

思路:
两种做法
一种是堆
一种是二分
看到这题的时候想到了这两种做法但又不知道具体咋做 - -

第一种堆思路
设置一个pair类型的堆
每次就插入从1×m到n×m的元素依次插入值与左边下标进入堆中
然后算第k大的时候就每次找堆顶元素
把堆顶元素减去一个下标再放入堆中(这样就代表了n*(m-1)的元素进入了堆中
然后反复操作找第k大即可
时间复杂度是 nlogn+klogn

堆代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
priority_queue<pair<ll,ll>>q;
int main()
{
    ll n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
           q.push(make_pair(i*m,i));
    }
    pair<ll,ll>temp;
    while(--k){
        temp=q.top();
        q.pop();
        temp.first-=temp.second;
        q.push(temp);
    }
    cout<<q.top().first;
    return 0;
}

第二种思路
二分
把思路转化成求第k小的数字
把答案设为ans
建一个1到n的for循环(下标为i)
如果 ans/i >= m就说明肯定它前面至少是有m个数字的
小于的时候ans/i就是它前面数字的答案了
那么直接check的时候算ans+=min(ans/i,m)
然后二分就好了

二分代码:

#include <iostream>

using namespace std;
typedef long long ll;
ll n,m,k;
int check(ll x){
   ll ans=0;
   for(int i=1;i<=n;i++){
        ans+=min(m,x/i);
   }
   return ans>=k;
}

int main()
{
    cin>>n>>m>>k;
    ll l=0,r=1e13;
    ll mid;
    k=n*m-k+1;//转化为第k小数字
    ll ans=0;
    while(l<=r){
            mid=l+(r-l)/2;
        if(check(mid)){
            ans=mid,r=mid-1;//ans为最后一次mid符合要求的情况
        }else l=mid+1;
    }
    cout<<ans<<endl;
    return 0;
}