题目:
http://poj.org/problem?id=3685
题意:
求出n*n矩阵中第m小的数. 矩阵中的数满足 num(i,j) = i2 + 100000 × i + j2 - 100000 × j + i × j.
思路:
两次二分,第一次二分矩阵中的数字, 最开始的左值和右值要设好.
由矩阵可看出,每一列的数随i 单调递增,所以看判断第一个mid是否符合时可以:枚举列数,二分行数. 复杂度是nlogn.
AC.
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll n, m;
ll cal(ll a, ll b)
{
return a*a + b*b + a*b + 1e5 * (a-b);
}
bool can(ll x)
{
ll ans = 0;
for(int j = 1; j <= n; ++j) {
ll l = 0, r = n + 1;
while(r - l > 1) {
ll mid = l + ((r-l)>>1);
if(cal(mid, j) <= x)
l = mid;
else r = mid;
}
ans += l;
if(ans >= m) return false;
}
return true;
}
void solve()
{
ll l = -100000*n, r = 3*n*n + 100000*n;
while(r - l > 1) {
ll mid = l + ((r-l)>>1);
if(can(mid)) l = mid;
else r = mid;
}
printf("%I64d\n", r);
}
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%I64d %I64d", &n, &m);
solve();
}
return 0;
}