Atcoder Beginner Contest 155D(二分,尺取法,细节模拟)

二分,尺取法,细节模拟,尤其是要注意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 }
保持热爱 不懈努力 不试试看怎么知道会失败呢(划掉) 世上无难事 只要肯放弃(划掉)
原文地址:https://www.cnblogs.com/ldudxy/p/12323525.html