poj 3685 Matrix(二分搜索之查找第k大的值)

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

 

Source

 

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

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

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<math.h>
 6 #include<stdlib.h>
 7 using namespace std;
 8 #define inf 1<<30
 9 #define ll long long
10 #define N 50006
11 ll n,m;
12 ll cal(ll i,ll j){
13     return i*i+100000*i+j*j-100000*j+i*j;
14 }
15 bool solve(ll mid){
16     ll cnt=0;
17     for(ll j=1;j<=n;j++){
18         ll low=1;
19         ll high=n+1;
20         while(low<high){
21             ll tmp=(low+high)>>1;//另外的写法
22             ll ans=cal(tmp,j);
23             if(ans>=mid){
24                 high=tmp;
25             }
26             else{
27                 low=tmp+1;
28             }
29         }
30         cnt+=low-1;//另外的写法
31     }
32     if(cnt>=m) return true;
33     return false;
34 }
35 int main()
36 {
37     int t;
38     scanf("%d",&t);
39     while(t--){
40 
41         scanf("%I64d%I64d",&n,&m);
42         ll low=-1e12;
43         ll high=1e12;
44 
45         while(low<high){
46             ll mid=(low+high)>>1;//另外的写法
47             if(solve(mid)){
48                 high=mid;
49             }
50             else{
51                 low=mid+1;
52             }
53         }
54         printf("%I64d\n",low-1);//另外的写法
55 
56     }
57     return 0;
58 }
View Code

 

 

另外的写法,试比较

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<math.h>
 6 #include<stdlib.h>
 7 using namespace std;
 8 #define inf 1<<30
 9 #define ll long long
10 #define N 50006
11 ll n,m;
12 ll cal(ll i,ll j){
13     return i*i+100000*i+j*j-100000*j+i*j;
14 }
15 bool solve(ll mid){
16     ll cnt=0;
17     for(ll j=1;j<=n;j++){
18         ll low=1;
19         ll high=n+1;
20         ll tmp=(low+high)>>1;
21         while(low<high){
22             ll ans=cal(tmp,j);
23             if(ans>=mid){
24                 high=tmp;
25             }
26             else{
27                 low=tmp+1;
28             }
29             tmp=(low+high)>>1;
30         }
31         cnt+=tmp-1;
32     }
33     if(cnt>=m) return true;
34     return false;
35 }
36 int main()
37 {
38     int t;
39     scanf("%d",&t);
40     while(t--){
41 
42         scanf("%I64d%I64d",&n,&m);
43         ll low=-1e12;
44         ll high=1e12;
45         ll mid=(low+high)>>1;
46         while(low<high){
47             if(solve(mid)){
48                 high=mid;
49             }
50             else{
51                 low=mid+1;
52             }
53             mid=(low+high)>>1;
54         }
55         printf("%I64d\n",mid-1);
56 
57     }
58     return 0;
59 }
View Code

 

posted @ 2015-09-04 20:18  UniqueColor  阅读(234)  评论(0编辑  收藏  举报