POJ 3685 Matrix (二分套二分)

Matrix
Time Limit: 6000MS   Memory Limit: 65536K
Total Submissions: 8674   Accepted: 2634

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 ≤ 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

 

题意:定义矩阵中(i,j)位置的值为(i^2+j^2+i*j+100000*(i-j)

求n*n矩阵中第m小的数

 

题解:首先打表或者推式子发现列是单调递增的,所以可以考虑二分答案,对于每一列二分找到有几个数比他小,然后就可以nlogn作出总共有几个数比他小,然后就搞定了

 

代码如下:

#include<cmath>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson ch[x][0]
#define rson ch[x][1]
#define hi puts("hi!");
#define int long long
using namespace std;

int n,m;

int get(int ith,int jth)
{
    return ith*ith+100000ll*ith-100000ll*jth+jth*jth+ith*jth;
}

int find(int x,int jth)
{
    int l=0,r=n,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(get(mid,jth)<=x)
        {
            l=mid;
        }
        else
        {
            r=mid-1;
        }
        if(r-l<=1) 
        {
            if(get(r,jth)<=x) mid=r;
            else mid=l;
            break;
        }
    }
    return mid;
}

int check(int x)
{
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        cnt+=find(x,i);
    }
    if(cnt>=m) return 1;
    else return 0;
}

signed main()
{
    int ttt;
    scanf("%lld",&ttt);
    while(ttt--)
    {
        int ans;
        scanf("%lld%lld",&n,&m);
        int l=-1e12,r=1e12,mid;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(check(mid))
            {
                ans=mid;
                r=mid-1;
            }
            else
            {
                l=mid+1;
            }
        }
        printf("%lld\n",ans);
    }
}

 

posted @ 2018-09-11 11:14  Styx-ferryman  阅读(158)  评论(0编辑  收藏  举报