二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
前提:有序数组!
下面提供一段二分查找实现的伪代码:
BinarySearch(max,min,des)
mid-<(max+min)/2
while(min<=max)
mid=(min+max)/2
if mid=des then
return mid
elseif mid >des then
max=mid-1
else
min=mid+1
return max
Description
Given a N × N matrix A, whose element in the i-th row and j-th column Aij is an number that equals i2 + 100000 × i + j2 - 100000 × j + i × j, you are to find the M-th smallest element in the matrix.
Input
The first line of input is the number of test case.
For each test case there is only one line contains two integers, N(1 ≤ N ≤ 50,000) and M(1 ≤ M ≤ N × N). There is a blank line before each test case.
Output
For each test case output the answer on a single line.
Sample Input
12
1 1
2 1
2 2
2 3
2 4
3 1
3 2
3 8
3 9
5 1
5 25
5 10
Sample Output
3
-99993
3
12
100007
-199987
-99993
100019
200013
-399969
400031
-99939
hint:
Hint:
1.注意long long
2.2500000000个数直接排序的话是没有算法能在1秒内完成的
3.观察矩阵会发现固定j,元素的值会随i递增,因此如果我们知道了某个值K,可以对每一列采用二分查找的方法在O(NlogN)的时间内找出矩阵中有多少个数小于K
4.显然矩阵中小于K的元素的个数也是随K递增的,因此用跟3相同思想的某种方法可以使整个算法的时间复杂度维持在O(TNlogNlogL)以内,其中L是矩阵的值域大小
5.师兄只能提示到这里了←_←
6.注意long long,因为真的很容易出错所以提醒两遍
#include <stdio.h>
#define f(i, j) i*i + 100000 * i + j * j - 100000 * j + i * j
//能够大大增加程序的效率!!!
#define maxn 1e12
#define minn -1e12
typedef long long ll;
//此题大量使用long long类型,因而可以宏定义,简化程序。
int n, m;
//使用全局变量来串连函数和main
ll search(ll x) {
int i;
ll num = 0;
ll max, min, mid;
for (i = 1; i <= n; i++) {
max = n + 1, min = 1;
mid = (max + min) >> 1;
while (max > min) {
if (f(mid, i) >= x) {
max = mid;
} else {
min = mid + 1;
}
mid = (max + min) >> 1;
}
num += mid - 1;
}
return num;
}
//用来计算在矩阵中比x小的数有多少个
int main() {
int total;
scanf("%d", &total);
while (total--) {
scanf("%d%d", &n, &m);
ll high = maxn;
ll low = minn;
ll mid = (high + low)>>1;
//思路是用取一个可能的最大值和一个可能的最小值和矩阵中的值进行二分搜索
while (low < high) {
if (search(mid) >= m) {
high = mid;
} else {
low = mid + 1;
}
mid = (low + high) >> 1;
}
printf("%lld\n", mid - 1);
}
return 0;
}