POJ 3685 Matrix 二分套二分
POJ 3685 Matrix 二分
题意
有一个N
阶方阵,方正中第i
行第j
列的元素值为\(d_{i,j}=i^{2}+1e5*i+j^{2}-1e5*j+i*j\),我们需要找出这个方阵中第M
小的元素值。
解题思路
分析这个公式,我们发现:当j
固定的时候,这个公式关于i
(取值范围:从0
到n
)是单调增加的,所以这里我们可以二分一个答案,然后一列一列的找小于(等于)它的个数,这样加起来我们就能知道我们枚举的这个答案是第几小了。
需要注意的是,第一个最外层的二分有点不同,因为我们二分的答案可能不存在,但是也是符合第m
小,这个情况还是需要注意的。但是题目好像并没有给出这样的判断。
对于二分的复习,参看关于详解二分。二分链接
代码实现
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <stack>
#include <queue>
#include <map>
typedef long long ll;
using namespace std;
const double esp = 1e-6;
const int inf = 0x3f3f3f3f;
const int MAXN = 1E6 + 7;
ll n, m;
ll fun(ll i, ll j) {
return i * i + 100000 * i + j * j - 100000 * j + i * j;
}
ll solve(ll value) {
ll sum = 0;
for (ll j = 1; j <= n; j++) {
ll left = 0, right = n + 1, ans = 0;
while (left < right) {
ll mid = left + (right - left) / 2;
if (fun(mid, j) <= value)
left = mid + 1;
else
right = mid;
}
if (left != 0)
sum += left - 1;
}
return sum;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%lld%lld", &n, &m);
ll lt = -1e12, rt = 1e12, ans;
while (lt < rt) {
ll mid = lt + (rt - lt) / 2;
if (solve(mid) >= m)
rt = mid;
else
lt = mid + 1;
}
printf("%lld\n", lt);
}
return 0;
}
欢迎评论交流!