Description
有一个N阶方阵 第i行,j列的值Aij =i2 + 100000 × i + j2 - 100000 × j + i × j,需要找出这个方阵的第M小值.
Input
第一行输入T代表测试组数.
每个测试用例包含2个数字N,M表示在N阶方阵找出第M大值, N(1 ≤ N ≤ 50,000) and M(1 ≤ M≤ N × N). 每两个测试用例之间可能有空行
Output
输出方阵的第M小值
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
Analysis
在二分m的大小之后,再次二分统计小于等于m的个数,但是可以有两个方向
我真的好蠢,调了一个下午...方向不太好
下面两个函数是等价的,一个关于i,一个关于j
f(i)=i2+(100000+j)×i+j2-100000×j
f(j)=j2+(i-100000)×j+i2+100000×i)
我们发现第一个函数的对称轴小于0,也就是在[1,n]的区间上是单调的,而第二个函数对称轴是有可能在[1,n]区间里的,所以要分类讨论
我就是写的第二种...所以有一点...
Code
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 #include<iostream> 9 #include<algorithm> 10 #define RG register ll 11 #define rep(i,a,b) for(RG i=a;i<=b;++i) 12 #define per(i,a,b) for(RG i=a;i>=b;--i) 13 #define ll long long 14 #define inf (1<<29) 15 #define cal(x,y) (y*y+(x-100000ll)*y+x*x+100000ll*x) 16 using namespace std; 17 ll T; 18 ll n,m; 19 inline ll read() 20 { 21 ll x=0,f=1;char c=getchar(); 22 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 23 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 24 return x*f; 25 } 26 27 ll check(ll lim) 28 { 29 ll cnt=0; 30 rep(i,1,n) 31 { 32 ll AOF=(100000ll-i)/2ll;//对称轴 33 if(n<=AOF) 34 { 35 ll l=1,r=n,mid,num,ans=0; 36 while(l<=r) 37 { 38 mid=l+r>>1,num=cal(i,mid); 39 if(num>lim) ans=mid,l=mid+1; 40 else r=mid-1; 41 } 42 cnt+=n-ans; 43 } 44 else 45 { 46 ll l=1,r=AOF,mid,num,ans=0; 47 while(l<=r) 48 { 49 mid=l+r>>1,num=cal(i,mid); 50 if(num>lim) ans=mid,l=mid+1; 51 else r=mid-1; 52 } 53 cnt+=AOF-ans;//bug! 54 55 l=AOF+1,r=n,mid,num,ans=AOF; 56 while(l<=r) 57 { 58 mid=l+r>>1,num=cal(i,mid); 59 if(num<=lim) ans=mid,l=mid+1; 60 else r=mid-1; 61 } 62 cnt+=ans-AOF; 63 } 64 } 65 return cnt>=m; 66 } 67 68 int main() 69 { 70 T=read(); 71 while(T--) 72 { 73 n=read(),m=read(); 74 ll l=cal(1ll,n),r=max(cal(n,1ll),cal(n,n)),mid,ans; 75 while(l<=r) 76 { 77 mid=l+r>>1; 78 if(check(mid)) ans=mid,r=mid-1; 79 else l=mid+1; 80 } 81 printf("%lld ",ans); 82 } 83 return 0; 84 }