POJ:3685-Matrix

Matrix

Time Limit: 6000MS Memory Limit: 65536K
Total Submissions: 7879 Accepted: 2374

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


解题心得:

  1. 给你一个n * n的矩阵,矩阵一点的值是i^2 + 100000 × i + j^2 - 100000 × j + i × j,问在整个矩阵中第m大的值是多少。
  2. 刚开始分解组合这个表达式弄了半天发现没啥用,后来才发现这个表达式就是用来观察单调性的,当j不变的时候i是单调递增的,然后这样就可以按照有序性来进行二分了。
  3. 先枚举一个值(O(logn)),然后遍历每一列(O(n)),在每一列中二分查找比枚举的那个值小的有多少个(O(log(n))),这样总的时间复杂度就是O(n(logn)^2);

#include <algorithm>
#include <stdio.h>
using namespace std;
typedef long long ll;

ll va(ll r, ll c){
    ll sum = r*r + 100000*r + c*c - 100000*c + r*c;
    return sum;
}

bool checke_col(ll ans,ll n,ll m) {
    ll num = 0;
    for(int j=1;j<=n;j++) {
        ll l = 0, r = n+1;
        while(r - l > 1) {
            ll mid = (l + r) >> 1;
            if(va(mid,j) < ans)
                l = mid;
            else
                r = mid;
        }
        num += l;
    }
    return num < m;
}

int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        ll l = -100000*n, r = n*n + 100000*n + n*n + n*n;
        while(r - l > 1){
            ll mid = (l + r) / 2;
            if(checke_col(mid,n,m)) l = mid;
            else r = mid;
        }
        printf("%lld\n",l);
    }
    return 0;
}
posted @ 2018-04-08 18:04  GoldenFingers  阅读(162)  评论(0编辑  收藏  举报