题意:
两个数组,元素个数分别为n和m。两两相乘可得n*m个数,求第k大的数。
思路:
本渣是听了别人二分的想法后才写出的。
两数组皆 非升序 排序。
首先,二分枚举第k大的数可能是多少。
假设当前枚举到mid,则计算大于等于mid的数有多少个。设之为tmp个。
若tmp > k,说明 第k大的数比mid大
若tmp < k,说明 第k大的数比mid小
若tmp = k, 分两种情况:
若n*m个数中存在等于mid的,则mid为第k大的数
否则,第k大的数比mid大
其中,在找大于等于mid的数有多少个时,采用的是枚举第一个数组,二分第二个数组的方法。
同理,在找是否存在等于mid的数也是采用同样的方法。
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define debug(x) <<#x<<":"<<(x)
const int maxn = 100010;
ll n, m, k;
ll boy[maxn], girl[maxn];
bool cmp(const ll a, const ll b) {
return a > b;
}
ll countAt(ll x, int i) {
int l = 0;
int r = m - 1;
while(l <= r) {
int m = l + r;
m >>= 1;
if(boy[i] * girl[m] < x)
r = m - 1;
else
l = m + 1;
}
return l;
}
ll count(ll x) {
ll result = 0;
for(int i = 0; i < n; i++)
result += countAt(x, i);
return result;
}
bool findAt(ll x, int i){
int l = 0;
int r = m - 1;
while(l <= r){
int m = l + r;
m >>= 1;
ll tmp = girl[m] * boy[i];
if(tmp == x)
return 1;
else if(tmp < x)
r = m - 1;
else
l = m + 1;
}
return 0;
}
bool find(ll x){
for(int i = 0; i < n; i++)
if(findAt(x, i))
return 1;
return 0;
}
ll solve() {
ll result = 0;
ll min = boy[n - 1] * girl[m - 1];
ll max = boy[0] * girl[0];
while(min <= max) {
ll mid = min + max;
mid >>= 1;
ll tmp = count(mid);
// cout debug(min)<<" " debug(max)<<" " debug(mid)<<" " debug(tmp)<<endl;
if(tmp == k) {
if(find(mid)) {
result = mid;
break;
} else
min = mid + 1;
} else if(tmp < k)
max = mid - 1;
else
min = mid + 1, result = mid;
}
return result;
}
int main() {
while(cin>>n >>m >>k) {
for(int i = 0; i < n; i++)
cin>>boy[i];
for(int i = 0; i < m; i++)
cin>>girl[i];
sort(boy, boy + n, cmp);
sort(girl, girl + m, cmp);
// for(int i = 0; i < n; i++)
// printf("%d ", boy[i]);
// puts("");
// for(int i = 0; i < m; i++)
// printf("%d ", girl[i]);
// puts("");
cout<<solve()<<endl;
}
return 0;
}