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
分析:一开始就推出了一般规律,想着打表矩阵然后查表ac的,没想到再n>25000时,矩阵的顺序就会变了,导致后面疯狂的wa,后来看了题解才知道,是个二分套二分的题目,其实我们可以发现当 j 不变的情况下,随着 i 的增大,Aij也相应增大,由这个受到启发,二分枚举第M小的数,然后按列寻找,找到第一个大于这个数的位置,就可以知道该列中有多少个数是大于这个数的了
#include<stdio.h>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<string>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define MAXN 100005*5
#define INF 0x3f3f3f3f//将近int类型最大数的一半,而且乘2不会爆int
#define MOD 1000000007
ll ccc(ll i, ll j)
{
return i * i + 100000 * i + j * j - 100000 * j + i * j;
}
int main()
{
int t;
cin >> t;
while (t--)
{
ll n, m;
scanf("%lld%lld", &n, &m);
ll l = -10000000000000LL, r = 1000000000000000LL;
ll mid, ans;
while (l <= r)
{
mid = (l + r) >> 1;
ll num = 0;
for (int i = 1; i <= n; ++i) //枚举每一列
{
ll L = 1, R = n, midd, tem = 0;
while (L <= R)
{
midd = (L + R) >> 1;
if (ccc(midd, i) <= mid)
{
tem = midd;
L = midd + 1;
}
else
R = midd - 1;
}
num += tem;//求出该列小于等于mid的个数
}
if (num < m)
l = mid + 1;
else //注意最小的那个数就是恰好的第k小的那个,因为再比他小的话,肯定没有k个
{
ans = mid;
r = mid - 1;
}
}
cout << ans << '\n';
}
return 0;
}
最后附上我规律打表疯狂wa的代码纪念一下:
#include<stdio.h>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<string>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define MAXN 100005*5
#define INF 0x3f3f3f3f//将近int类型最大数的一半,而且乘2不会爆int
#define MOD 1000000007
ll a[MAXN], b[MAXN];
void init() {
ll ret = 1;
a[0] = 0;
for (ll i = 1; i <= 50005; ++i) {
a[i] = a[i - 1] + ret;
ret++;
}
}
int main()
{
init();
ll t;
cin >> t;
while (t--) {
memset(b, 0, sizeof(b));
ll n, m;
scanf("%lld %lld", &n, &m);
b[1] = n * (n + 1) / 2;
ll tem = n - 1;
for (ll i = 2; i <= n; ++i) {
b[i] = b[i - 1] + tem;
tem--;
}
ll x, y, cnt, flag=1;
for (ll i = 1; i <= n; ++i) {
if (m <= a[i]) {
flag = 0;
x = m - a[i - 1];
y = n-i+x;
break;
}
}
if (flag) {
for (ll i = 2; i <= n; ++i) {
if (m <= b[i]) {
y = m - b[i - 1];
x = i + y - 1;
break;
}
}
}
ll sum = x * x + 100000 * x + y * y - 100000 * y + x * y;
cout << sum << '\n';
}
return 0;
}