题目
思路
这道题,通过观察可以发现公式可知,每一列都是单调递增的,但是每一行不一定单调的。所以,我们首先二分答案
m
i
d
mid
mid,然后按列枚举,在每一列中,因为具有单调性,从而可以二分出每一列中数值小于等于
m
i
d
mid
mid的数量,然后能够根据整个矩阵中计算出的
≤
\leq
≤mid的数量,进行二分答案。
注意:
- 最外层二分答案的时候,是要寻找满足条件的下界
- 里面嵌套的二分,是要寻找到满足条件的上界
- 这两个二分在代码的写法上有所不同
代码
(PS:POJ的c++真坑,好多好用的语法都不能用了,QAQ)
ll Cf(ll i,ll j){
return i * i + 100000ll * i + j * j - 100000ll * j + i * j;
}
ll Ccheck(ll mid,int n){
ll cnt = 0;
for (int j = 1; j <= n; j++) {
ll l = 0, r = n;//二分一列中,有多少元素小于等于mid,这里的二分是二分满足条件的上限
ll ans = 0;
while (l <= r) {
ll i = l + (r - l) / 2;
if (Cf(i, j) <= mid) {
ans = i;
l = i + 1;
} else r = i - 1;
}
cnt += ans;
}
return cnt;
}
void C() {
//二分套二分
int t;
cin >> t;
// auto f = [](ll i, ll j) -> ll {
// return i * i + 100000ll * i + j * j - 100000ll * j + i * j;
// };
// auto check = [&f](ll mid, int n) {
// //矩阵中有多少小于等于mid的元素
// //先枚举列,然后再次二分行
// ll cnt = 0;
// for (int j = 1; j <= n; j++) {
// ll l = 0, r = n;//二分一列中,有多少元素小于等于mid,这里的二分是二分满足条件的上限
// ll ans = 0;
// while (l <= r) {
// ll i = l + (r - l) / 2;
// if (f(i, j) <= mid) {
// ans = i;
// l = i + 1;
// } else r = i - 1;
// }
// cnt += ans;
// }
// return cnt;
// };
while (t--) {
ll n, m;
cin >> n >> m;
ll l = -1e12, r = 1e12;
while (l < r) {
//cout<<l<<r<<endl; //这里的二分是满足条件的下界
ll mid = l + (r - l) / 2;
if (Ccheck(mid, n) < m) {
l = mid + 1;
} else r = mid;
}
cout << l << endl;
}
}