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(取值范围:从0n)是单调增加的,所以这里我们可以二分一个答案,然后一列一列的找小于(等于)它的个数,这样加起来我们就能知道我们枚举的这个答案是第几小了。

需要注意的是,第一个最外层的二分有点不同,因为我们二分的答案可能不存在,但是也是符合第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;
}


posted @ 2020-02-03 20:33  ALKING1001  阅读(106)  评论(0编辑  收藏  举报