时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
给出一个长度为 n n n 的数列 A 1 , … , A n A_1, \dots, A_n A1,…,An 和一个长度为 m m m 的数列 B 1 , … , B m B_1, \dots, B_m B1,…,Bm ,可以构造得到一个 n × m n \times m n×m 的矩阵 C C C,其中 C i , j = A i × B j C_{i,j} = A_i \times B_j Ci,j=Ai×Bj 。
给出整数 K K K,你需要求出 C C C 中第 K K K 大的数的值。
第一行输入三个整数 n , m , K ( 1 ≤ n , m ≤ 1 0 5 , 1 ≤ K ≤ n × m ) n,m,K(1 \leq n,m \leq 10^5, 1\leq K \leq n \times m) n,m,K(1≤n,m≤105,1≤K≤n×m) 。
第二行输入 n n n 个空格隔开的整数 A 1 , . . . , A n ( − 1 0 6 ≤ A i ≤ 1 0 6 ) A_1,..., A_n(-10^6 \leq A_i \leq 10^6) A1,...,An(−106≤Ai≤106)
第三行输入 m m m 个空格隔开的整数 B 1 , . . . , B m ( − 1 0 6 ≤ B i ≤ 1 0 6 ) B_1,..., B_m (-10^6 \leq B_i \leq 10^6) B1,...,Bm(−106≤Bi≤106)
输出一行一个整数,表示矩阵中的第 K K K 大的数的值。
3 3 3
2 3 4
4 5 6
18
和 第K小分数(二分) 很相似的一道题,不过这个更复杂了些,矩阵里可以有 0 0 0 和负数,题解里对负数做了讨论,不过我却看到了大神更巧妙的写法。。。(原谅我菜的过分没考虑负数这玩意)
需要注意官方题解的逻辑是以 1 0 18 10^{18} 1018 为中心进行二分,而 m i d − 1 0 18 mid-10^{18} mid−1018 也就相当于以 0 0 0 为中心进行二分,跟一般写法无异,还有就是官方题解是计算的比检验值小的个数,因为之前已经把 k k k 转换成第 k k k 小的数字了(见于代码第43行)。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n, m;
long long K;
const int N = 110000;
vector<int> A[3], B[3];
long long get(long long lim) {
if (lim >= 0) {
long long ans = (long long)(A[1].size())*m + (long long)(B[1].size())*(n - A[1].size());
ans += 1ll * A[0].size()*B[2].size() + 1ll * A[2].size()*B[0].size();
for (int a = 0; a <= 2; a += 2) {
int b = a;
int now = int(B[b].size()) - 1;
for (int i = 0; i < A[a].size(); ++i) {
while (now >= 0 && 1ll * A[a][i] * B[b][now] > lim) now--;
ans += now + 1;
}
}
return ans;
}
else if (lim < 0) {
long long ans = 0;
for (int a = 0; a <= 2; a += 2) {
int b = 2 - a;
int now = int(B[b].size()) - 1;
for (int i = 0; i < A[a].size(); ++i) {
while (now >= 0 && 1ll * A[a][i] * B[b][now] >= lim) now--;
ans += int(B[b].size()) - now - 1;
}
}
return ans;
}
}
int main() {
scanf("%d%d%lld", &n, &m, &K);
K = 1ll * n*m - K + 1;
for (int i = 1; i <= n; i++) {
int k1; scanf("%d", &k1);
if (k1 > 0) A[0].push_back(k1);
else if (k1 == 0) A[1].push_back(k1);
else A[2].push_back(-k1);
}
for (int i = 1; i <= m; i++) {
int k1; scanf("%d", &k1);
if (k1 > 0) B[0].push_back(k1);
else if (k1 == 0) B[1].push_back(k1);
else B[2].push_back(-k1);
}
for (int i = 0; i < 3; i++) {
sort(A[i].begin(), A[i].end());
sort(B[i].begin(), B[i].end());
}
long long l = 0, r = 2e18, ans = 0, bias = 1e18;
while (l < r) {
long long mid = (l + r >> 1);
if (get(mid - bias) >= K) {
ans = mid - bias; r = mid;
}
else l = mid + 1;
}
cout << ans << endl;
}
#include
#include
#include
#include
#define LL long long
using namespace std;
const int maxn = 1e5 + 5;
LL a[maxn], b[maxn];
LL n, m, k;
bool che(LL mid) {
LL num = 0;
for (int i = 1; i <= m; i++) {
if (b[i] == 0) num += mid < 0 ? n : 0;
if (b[i] < 0) num += lower_bound(a + 1, a + n + 1, ceil((double)mid / b[i])) - (a + 1);
if (b[i] > 0) num += n - ((upper_bound(a + 1, a + n + 1, floor((double)mid / b[i]))) - (a + 1));
}
return num <= k;
}
int main() {
cin >> n >> m >> k;
k--;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= m; i++) scanf("%lld", &b[i]);
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
LL l = -1e13, r = 1e13;
while (l + 1 < r) {
LL mid = (l + r) >> 1;
if (che(mid))r = mid;
else l = mid;
}
cout << r << endl;
return 0;
}