二分,尺取法,细节模拟,尤其是要注意a[i]被计算到和a[i]成对的a[j]里时
1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 long long a[200007]; 5 int n; 6 long long k; 7 bool check(long long x){ 8 long long sum=0;//比x小的个数 9 for(int i=1;i<=n;++i){ 10 if(a[i]!=0){ 11 long long flag=x/a[i]; 12 if(x%a[i]){ 13 if(x>0&&a[i]<0){//x=5,a[i]=-2,flag=-2 14 sum+=n+1-(lower_bound(a+1,a+1+n,flag)-a);//[-2,∞) 15 if(a[i]>=flag)//如果a[i]也在上面sum加过的范围内 16 --sum;//去掉a[i]自己,自己不能和自己成对 17 } 18 else if(x>0&&a[i]>0){//x=5,a[i]=2,flag=2,flag+1=3 19 sum+=(lower_bound(a+1,a+1+n,flag+1)-a)-1;//[2,∞) 20 if(a[i]<=flag)//如果a[i]也在上面sum加过的范围内 21 --sum;//去掉a[i]自己,自己不能和自己成对 22 } 23 else if(x<0&&a[i]<0)//和以上类似 24 sum+=n+1-(upper_bound(a+1,a+1+n,flag)-a); 25 else if(x<0&&a[i]>0) 26 sum+=(lower_bound(a+1,a+1+n,flag)-a)-1; 27 } 28 else{ 29 if(x>0&&a[i]<0){ 30 sum+=n+1-(upper_bound(a+1,a+1+n,flag)-a); 31 if(a[i]>flag) 32 --sum; 33 } 34 else if(x>0&&a[i]>0){ 35 sum+=(lower_bound(a+1,a+1+n,flag)-a)-1; 36 if(a[i]<flag) 37 --sum; 38 } 39 else if(x<0&&a[i]<0) 40 sum+=n+1-(upper_bound(a+1,a+1+n,flag)-a); 41 else if(x<0&&a[i]>0) 42 sum+=(lower_bound(a+1,a+1+n,flag)-a)-1; 43 else if(x==0&&a[i]<0) 44 sum+=n+1-(upper_bound(a+1,a+1+n,0)-a); 45 else if(x==0&&a[i]>0) 46 sum+=(lower_bound(a+1,a+1+n,0)-a)-1; 47 } 48 } 49 else if(a[i]==0&&x>0) 50 sum+=n-1; 51 } 52 sum>>=1;//除以二,同一对被计算了两次 53 return sum<k;//如果比x小的不到k个,那么答案还会更大 54 } 55 int main(){ 56 ios::sync_with_stdio(false); 57 cin.tie(NULL); 58 cout.tie(NULL); 59 cin>>n>>k; 60 for(int i=1;i<=n;++i) 61 cin>>a[i]; 62 sort(a+1,a+1+n); 63 long long l=-1e18,r=1e18; 64 long long ans=0; 65 while(l<=r){ 66 long long mid=(l+r)>>1; 67 if(check(mid)){//此时比mid小的不到k个,答案可能可以更大,正确答案是比mid小的正好是k-1个 68 ans=mid; 69 l=mid+1; 70 } 71 else 72 r=mid-1; 73 } 74 cout<<ans; 75 return 0; 76 }