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 ≤ 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
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); } }