http://poj.org/problem?id=3685
查找第k大的值。由于有50000*50000个点,因此采用二分查找+检验正确性的方法。本题是二分套二分,很经典。
解题思路:
观察发现i2 + 100000 × i + j2 - 100000 × j + i × j关于i单调递增,所以每一列是单调的,可以使用二分查找每一列小于x的数的个数后累加进行判断。
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <queue>
#include <map>
using namespace std;
int n;
long long m;
long long Cal(long long x){
long long ret = 0;
for(int j = 1; j <= n; j++){
int l = 1, r = n, ans = 0;
while(l <= r){
int mid = (l + r) >> 1;
long long y = 1ll * mid * mid + 100000ll * mid + 1ll * j * j - 100000ll * j + 1ll * mid * j;//防止中途爆int,导致出错
if(y < x) l = mid + 1, ans = mid;//使y < x的最大行数就是这一列中小于x的个数
else r = mid - 1;
}
ret += ans;
}
return ret;
}
int main(){
int ca;
cin >> ca;
while(ca--){
cin >> n >> m;
long long l = -1e18, r = 1e18, ans = 0;
while(l <= r){
long long mid = (l + r) >> 1;
if(Cal(mid) < m) l = mid + 1, ans = mid;//第K小的数性质是最多有K-1个数比它小,当ans最大时就是我们要寻找的数
else r = mid - 1;
}
cout << ans << endl;
}
return 0;
}