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
题目大意:题目意思很简单。这个题目乍一看,先打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 ",low-1);//另外的写法 55 56 } 57 return 0; 58 }
另外的写法,试比较
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 ",mid-1); 56 57 } 58 return 0; 59 }