zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    idea
    Docker
    建张表
    MySQL 时间字段默认值
    获取唯一字符串
    Java避免空指针
    Android自定义控件
    Android 中textview显示富文本信息
    apktool反编译详细使用教程
    【android动态布局】之【ListView动态加载数据模板(使用xml布局)】
  • 原文地址:https://www.cnblogs.com/ZefengYao/p/6388768.html
Copyright © 2011-2022 走看看