POJ 3685Matrix(两次二分)

来源:互联网 发布:nginx怎么配置ssl证书 编辑:程序博客网 时间:2024/05/21 22:48
Matrix
Time Limit: 6000MS Memory Limit: 65536KTotal Submissions: 4237 Accepted: 1037

Description

Given a N × N matrix A, whose element in the i-th row andj-th columnAij is an number that equalsi2 + 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

121 12 12 22 32 43 13 23 83 95 15 255 10

Sample Output

3-99993312100007-199987-99993100019200013-399969400031-99939

Source

POJ Founder Monthly Contest – 2008.08.31, windy7926778

           

          题目大意:题目意思很简单。这个题目乍一看,先打n为比较小例如8的表,会觉得很有规律,大小规律是从右上往左下依次增大,但是这个规律到n为5*10^4就不一定保持了。

 

           解题思路:有一个规律是看得见的,j不变i增大函数值也在增大。根据这个可以对这n列二分得到<x的值,同样所求的x也是可以二分慢慢靠近最后的结果,我处理得到最后的结果是个数为m+1的最小值,所以最后mid-1即为答案。

 

           题目地址:Matrix

 

AC代码:

#include<iostream>#include<string>#include<cstdio>using namespace std;typedef long long ll;ll n,m;int flag;  //二分必须是出现过的元素ll cal(ll i,ll j){    return  i*i+100000*i+j*j-100000*j+i*j;}ll fun(ll x){    ll num=0;    ll i,l,r,midd;    for(i=1; i<=n; i++)    {        l=1,r=n+1;  //需要找小于x的个数        midd=(l+r)>>1;        while(l<r)        {            if(cal(midd,i)>=x) r=midd;            else l=midd+1;            midd=(l+r)>>1;        }        num+=midd-1;  //有可能一个也没有l=1个数就为0    }    return num;}int main(){    int tes;    scanf("%d",&tes);    while(tes--)    {        scanf("%lld%lld",&n,&m);        ll left,right,mid;        left=-1e12,right=1e12;        mid=(left+right)>>1;        while(left<right)        {            if(fun(mid)>=m) right=mid;            else left=mid+1;            mid=(left+right)>>1;        }        //找的指实际上是m+1个数里面最小的,mid-1即为答案        printf("%lld\n",mid-1);    }    return 0;}//1266MS


 

 

原创粉丝点击