题目大意:给定NXN的矩阵,第i行第j列的值Aij = i2 + 100000 × i + j2 - 100000 × j + i × j, N不超过5万。求第M小的数。
这题仍然是用二分搜索,设C(X):=矩阵中值不小于X的个数不少于K。至于如何判断命题为真,可以发现这个等式的值是逐行单调递增的,所以可以对每一列再进行二分搜索,找出不小于X的个数就可以了。
#include <stdio.h>
#include <vector>
#include <math.h>
#include <string.h>
#include <string>
#include <iostream>
#include <queue>
#include <list>
#include <algorithm>
#include <stack>
#include <map>
using namespace std;
bool CC(long long x, int n, long long k)
{
long long curcount = 0;
int l = -1;
for (int i = 1; i <= n; i++)
{
l = 0;
int r = n + 1;
while (r - l > 1)
{
long long mid = (r + l) / 2;
if (mid * mid + 100000 * mid + i * i - 100000 * i + mid * i >= x)
{
r = mid;
}
else
l = mid;
}
curcount += (n - r + 1);
if (curcount >= k)
{
return true;
}
}
if (curcount < k)
{
return false;
}
else
return true;
}
int main()
{
#ifdef _DEBUG
freopen("d:\\in.txt", "r", stdin);
#endif
int k;
scanf("%d", &k);
for (int i = 0; i < k; i++)
{
long long n, m;
scanf("\n%I64d %I64d\n", &n, &m);
//qsort(values, n, sizeof(int), compp);
long long l = 50000 * (long long)50000 - 100000LL * 50000;
long long r = 50000LL * 50000LL * 3 + 1;
long long k = (long long)n * n - m + 1;
while (r - l > 1)
{
long long mid = (r + l) / 2;
if (CC(mid, n, k))
{
l = mid;
}
else
r = mid;
}
printf("%I64d\n", l);
}
return 1;
}