poj 3685 Matrix

                                                                                                                                   Matrix
Time Limit: 6000MS   Memory Limit: 65536K
Total Submissions: 6448   Accepted: 1858

Description

Given a N × N matrix A, whose element in the i-th row and j-th column Aij is an number that equals i2 + 100000 × i + j2 - 100000 × j + i × j, you are to find the M-th smallest element in the matrix.

Input

The first line of input is the number of test case.
For each test case there is only one line contains two integers, N(1 ≤ N ≤ 50,000) and M(1 ≤ M ≤ N × N). There is a blank line before each test case.

Output

For each test case output the answer on a single line.

Sample Input

12

1 1

2 1

2 2

2 3

2 4

3 1

3 2

3 8

3 9

5 1

5 25

5 10

Sample Output

3
-99993
3
12
100007
-199987
-99993
100019
200013
-399969
400031
-99939


题意: 题目中给出了一个N*N阶的矩阵,矩阵中第i行第j列的元素Aij的值等于i

2

+ 100000 × i + j

2

- 100000 × j + i × j ,
要找到这个矩阵元素中第k小的元素。
思路:可以发现对于矩阵的每一行或者每一列的所有元素而言,元素值的变化都是单调的,我们选其一,讨论每一列的元素,每一列元素从上到下是单调递增的。
因此我们可以用两重的二分法解决该问题。第一重二分用于搜索第k小的元素的值,对于每一个找到的值,再用一次二分用于检验该值是否是第k小的元素。
故第一重二分的判断条件可以为C1:比该元素小的值是否小于k个,如果true,则真正要找的元素比当前元素可能还要大一点。
第二重二分判断条件C2:对于每一列分别进行判断,在每一列中分别找到比当前元素的小的元素的个数并累加之。总和即是第一重二分需要判断的比该元素小的元素的个数
AC代码:
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
#include<numeric>
#include<cstring>
using namespace std;
typedef long long ll;
const int N_MAX = 50000;
ll n, m;
ll f(const ll&i, const ll&j) {
    return (i*i + j*j + 100000 * i - 100000 * j + i*j);
}

bool C(const ll&mid) {//判断mid是不是第m小的值,false表示比mid小的数量大于等于m个,说明mid太大
    ll smaller_num = 0;                                //比mid小的数必须正好有m-1个才行
    for (int i = 1; i < n+1;i++) {//对于每一行而言,都要进行二分搜索,千万注意行列最好要从1取,计算元素值有用
        int lb = 0, ub = n + 1;
        while (ub - lb > 1) {
            int mid2 = (ub + lb) >>1;
            if (f(mid2, i) < mid)lb=mid2;
            else ub = mid2;
        }
        smaller_num += lb;
    }
    return smaller_num < m;
}

int main() {
    int t;
    scanf("%d",&t);
    while (t--) {
        scanf("%lld%lld",&n,&m);
        ll lb = -100000*n,ub=3*n*n+100000*n;
        while (ub-lb>1) {
            ll mid = (lb + ub) >>1;
                if (C(mid))lb = mid;//[lb,ub)
                else ub = mid;
        }
        printf("%lld
",lb);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZefengYao/p/6388768.html