二分法 hrbeu 1211

思路:由于N<=10000 ,所以我们不可能吧集合C中的元素全部算出来O(n^2),显然不行,这样的话,你还没求出集合C就已经TLE,根本没时间求第k大的值。

所以我们要换种角度,题目要求我们求集合c中第k大的数(用num_k表示),我们只要找出集合C中<=num_k的元素个数为m=n^2-k+1个即可。

这样我们先对A集合与B集合元素进行排序,先锁定集合C中元素的范围,在这个范围里面进行二分,再在这个二分里嵌套二分求<=当前num_k的元素的个数less_num。无限的去逼近num_k。

/*
* hrbeu1211.c
*
* Created on: 2011-9-19
* Author: bjfuwangzhu
*/

#include
<stdio.h>
#include
<stdlib.h>
#define nmax 10001
int numa[nmax], numb[nmax], n, k;
int cmp(const void *a, const void *b) {
return *(int *) a - *(int *) b;
}
int bbsearch(int key, int m) {
int i, left, right, mid, mm;
for (i = 0, mm = 0; i < n; i++) {
left
= 0, right = n - 1;
while (left <= right) {
mid
= (left + right) >> 1;
if (numa[i] * numb[mid] > key) {
right
= mid - 1;
}
else {
left
= mid + 1;
}
}
mm
+= left;
if (mm > m) {
break;
}
}
return mm;
}
void solve() {
int left, right, mid, mm, m;
m
= n * n - k + 1;
left
= numa[0] * numb[0], right = numa[n - 1] * numb[n - 1];
while (left <= right) {
mid
= (left + right) >> 1;
mm
= bbsearch(mid, m);
if (mm >= m) {
right
= mid - 1;
}
else {
left
= mid + 1;
}
}
printf(
"%d\n", left);
}
int main() {
#ifndef ONLINE_JUDGE
freopen(
"data.in", "r", stdin);
#endif
int t, i;
while (~scanf("%d", &t)) {
while (t--) {
scanf(
"%d %d", &n, &k);
for (i = 0; i < n; i++) {
scanf(
"%d", numa + i);
}
for (i = 0; i < n; i++) {
scanf(
"%d", numb + i);
}
qsort(numa, n,
sizeof(numa[0]), cmp);
qsort(numb, n,
sizeof(numb[0]), cmp);
solve();
}
}
return 0;
}

原文地址:https://www.cnblogs.com/xiaoxian1369/p/2181207.html