题目描述
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
解题思路:
通过分析已知的方程我们知道:该方程在j固定而i增大时增大,而i固定j增大时就不一定了,那么我们就按列遍历,设定一个x,我们统计每一列中<=x的数的个数,即查找这一列中这个数x的lower_bound,然后我们把他们加起来与目标m进行比较,以此为判断条件对x进行二分。
试想,我现在有一个x,然后我看看每一列有多少个小于等于x的数,把他们加起来就是矩阵中小于等于x的数的个数,我们要求的是矩阵中第m小的数,也就是说如果这个数是x,那么矩阵中有m个小于等于x的数(当然最大的那个要是x),这样我们就可以二分x,让他逼近矩阵中有m个小于等于x的数这个条件,直至求出x。
AC代码:
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <vector>
#include <bitset>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const long long LINF = 1e14;
const double PI = acos(-1.0);
const int MAXN = 3e5+10;
ll n, m;
ll f(ll x, ll y)
{
return x*x + y*y + x*y + 100000*(x - y);
}
bool judge(ll x) //判断矩阵中<=x的数的个数是否>=m
{
ll res = 0;
for(int i = 1; i <= n; i++) //按列遍历
{
int low = 0, up = n + 1;
while(up - low > 1)
{
int mid = (up + low) / 2;
if(f((ll)mid, (ll)i) >= x) up = mid;
else low = mid;
}
res += low; //把每一列<=x的数的个数加起来
}
return res >= m;
}
int main()
{
int t;
cin >> t;
while(t--)
{
scanf("%lld%lld", &n, &m);
ll low = -LINF, up = LINF;
while(up - low > 1)
{
ll mid = (up + low) >> 1;
if(judge(mid)) up = mid;
else low = mid;
}
printf("%lld\n", low);
}
return 0;
}