Solution to a problem AT4867 [[ABC155D] Pairs]

Title
twice dichotomy
First ans divided by two, in \ ([- 10 ^ {18}, {18} ^ 10] \) between
consider how to check
for each ans, each enumeration \ (a_i \) , bipartite Find a few \ (a_j \) , so that \ (a_i \ times a_j <ans
\) for each pair of legitimate \ ((a_i, a_j) \) , to enumerate \ (a_i \) and \ (a_j \) when all was to find it again, so in the end should come and weight divided by 2
because they can not appear \ (a_i = a_j \) , so when the return should \ (i = j \) in the case of removing the
two arrays a, b
a number input in the ascending order, a descending order in the row b
in the second two time-sharing, when the \ (a_i <0 \) , b using binary array (negative negative positive, so at this time the absolute value of greater when the negative is "large", because it \ (a_i \) larger product), when the \ (a_i \ GEQ 0 \) , with a array, thus ensuring that the can-half of
the first layer two points, we in fact, is found in the n \ (a_i \)Twenty-two obtained by multiplying the number, greater than the minimum number of large number of small to k, so the output \ (ans-1 \)
complexity \ (O (n \ log n \ log 10 ^ {18}) \)
code.

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define R register
#define EN std::puts("")
#define LL long long
inline LL read(){
    LL x=0,y=1;
    char c=std::getchar();
    while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    return y?x:-x;
}
//a:abs大的负数->abs小的负数->小正数->大正数
//b:大正数->小正数->abs小的负数->abs大的负数 
int n,fir;//a[fir]是a数组中第一个非负数
LL k;
LL a[200006],b[200006];
inline int finda(int i,LL ans){
    R int l=1,r=n,mid,ret=0;
    while(l<=r){
        mid=(l+r)>>1;
        if(a[mid]*a[i]<ans) ret=mid,l=mid+1;
        else r=mid-1;
    }
    return ret>=i?(ret-1):ret;//如果ret>=i,说明其中有一对是两个a[i]相乘得到,此时要减1
}
inline int findb(int i,LL ans){
    R int l=1,r=n,mid,ret=0;
    while(l<=r){
        mid=(l+r)>>1;
        if(b[mid]*a[i]<ans) ret=mid,l=mid+1;
        else r=mid-1;
    }
    return (ret+i>n)?(ret-1):ret;//同理,但b是倒序
}
inline int check(LL ans){
    LL nowk=0;
    for(R int i=1;i<fir;i++)//负数 
        nowk+=findb(i,ans);
    for(R int i=fir;i<=n;i++)//正数
        nowk+=finda(i,ans);
    nowk/=2;//去重
    return nowk>=k;
}
inline int cmp(int x,int y){
    return x<y;
}
int main(){
    n=read();k=read();
    for(R int i=1;i<=n;i++) a[i]=read(); 
    std::sort(a+1,a+1+n,cmp);
    fir=n+1;
    for(R int i=1;i<=n;i++)
        if(a[i]>=0){fir=i;break;}
    for(R int i=1;i<=n;i++) b[n-i+1]=a[i];//存入b数组,对负数二分时使用
    R LL l=-1e18,r=1e18,mid,ans;
    while(l<=r){
        mid=(l+r)/2;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    std::printf("%lld",ans-1);
    return 0;
}

Guess you like

Origin www.cnblogs.com/suxxsfe/p/12527510.html