题目大意:给出一个N*N的矩阵,第i行第j列的值为i*i + 100000*i + j*j - 100000*j + i*j,求矩阵中第M小的数
分析:由i*i + 100000*i + j*j - 100000*j + i*j这个公式,可知i是单调递增的。所以,我们可以第一次二分答案mid,第二次根据i的单调性依次二分每一列,得到比mid小的数的个数,如果总个数小于M的话,则说明mid小了。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL T, N, M;
LL f(LL i, LL j) {
return i*i + 100000*i + j*j - 100000*j + i*j;
}
//mid是否是第M小的数
bool C(LL mid) {
LL cnt = 0; //统计比mid小的数
for(LL j = 1; j <= N; j++) {
LL L = 0, R = N+1;
while(R-L > 1) {
LL i = (L+R)>>1;
if(f(i, j) < mid) L = i;
else R = i;
}
cnt += L;
}
return cnt < M;
}
int main() {
scanf("%lld", &T);
while(T--) {
scanf("%d%d", &N, &M);
LL L = -100000*N, R = N*N+100000*N+N*N+N*N;
while(R-L > 1) {
LL mid = (L+R)>>1;
if(C(mid)) L = mid;
else R = mid;
}
printf("%lld\n", L);
}
return 0;
}