Poj 3685(经典二分)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Wiking__acm/article/details/9886865
Matrix
Time Limit: 6000MS   Memory Limit: 65536K
Total Submissions: 4150   Accepted: 1007

Description

Given a N × N matrix A, whose element in the i-th row andj-th column Aij is an number that equals i2 + 100000 ×i + j2 - 100000 × j + i × j, you are to find theM-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 ≤ MN × 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

Source

POJ Founder Monthly Contest – 2008.08.31, windy7926778

题目意思是给出一个矩阵,这个矩阵中各个元素的值由给定的公式确定。即:i2 + 100000 ×i + j2 - 100000 × j + i × j。开始打了个10*10的表,以为矩阵元素得大小顺序是有规律的,交了后wa了,发现还是不能乱搞。从该式子可以看出,结果随着i单调递增,但对j呢?求导后可发现不是单调递增的,所以找规律就是错的。求第k大元素嘛,还是考虑二分。二分的关键是怎么去判断。因为j无单调性可言,那么就枚举j,二分找出每列的小于mid的个数cntx,和小于等于mid的个数cnty。总复杂度就是logINF*n*logn,是可以接受的。然后根据相应逻辑判断即可。这道题,就是二分里再套二分,还是蛮有意思的。

#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<iostream>
#include<map>
using namespace std;
typedef long long LL;
const int maxn = 1000 + 5;
const LL INF = 1LL<<40;
LL n,m;

LL cal(LL i,LL j){
    return  i*i + 100000 * i + j*j - 100000 * j + i * j;
}

int can(LL x){
    LL cntx = 0,cnty = 0;
    for(LL i = 1;i <= n;i++){
        LL l = 1,r = n;
        LL tem = -1;
        while(l <= r){
            LL mid = l+(r-l)/2;
            if(cal(mid,i) < x){
                l = mid+1;
                tem = mid;
            }
            else {
                r = mid-1;
            }
        }
        if(tem != -1){
            cntx += tem;
        }
    }
    for(LL i = 1;i <= n;i++){
        LL l = 1,r = n;
        LL tem = -1;
        while(l <= r){
            LL mid = l+(r-l)/2;
            if(cal(mid,i) <= x){
                l = mid+1;
                tem = mid;
            }
            else {
                r = mid-1;
            }
        }
        if(tem != -1){
            cnty += tem;
        }
    }
    if(cnty < m){
        return 1;
    }
    else if(cntx > m-1){
        return -1;
    }
    else{
        return 0;
    }
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%I64d%I64d",&n,&m);
        LL l = -INF,r = INF;
        LL ans;
        while(l <= r){
            LL mid = l+(r-l)/2;
            int tag = can(mid);
            if(tag == 1){
                l = mid+1;
            }
            else if(tag == -1){
                r = mid-1;
            }
            else{
                ans = mid;
                break;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


展开阅读全文

没有更多推荐了,返回首页