ABC155D - Pairs

本题的模型是典型的求第k小问题,这个问题有2个不一样的点,一是任意选出2个数,不能是同一个,二是这个题有负数,那我们在原有的基础上就需要特判这两点,经典模型是2个数组相乘,此处是1个,那么一样可以枚举每一个数,计算比该数小的数的数量,运用容斥,将重复的去掉即可,第一个问题就解决了,假设要判断的数是a,当前枚举到的数是b,第二个问题就是有0有负数有正数,b=0的情况很简单,若a大于0,那么一定所有的数乘a都小于a,直接累加即可,b=正数的情况就比较经典,二分查找比a/b小的数,累加即可,b=负数呢,那就反过来找呗,找比a/b大的数,用二分查找大于等于a/b的数,N-数量就是累加量,因为a是负的,负的乘比他小的负的一定变大,则b*比a/b大的数一定小于a,本题还要注意一个点,在a/b时,若是异号相除,取整时会出问题,需要特判各种情况,当b>0时,我们找的是正向的<=区间,直接对a/b向下取整就可以了,当b<0时,我们找的是反向的>区间,我们也需要"向下取整",但这里的b是负数,我们直接用floor取整会导致统计到的数变多,举个例子,7/3取整为2,2*3<7,floor(7/-3)=-3,-3*(-3)>7,那我们就要反过来向上取整,用ceil,这样保证取整后的数*b<a,总之就是取整后的数一定要保证*b<a,如果有疑问可以自己举几个例子,7/-3,6/-3.-6/4,-6/3等

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long LL;

const int maxm = 2e5+5;
LL n, k;

LL buf[maxm];

bool check(LL x) {
    LL cnt = 0, i, j;
    for(i = 0; i < n; ++i) {
        if(buf[i]*buf[i] <= x) cnt--;
        if(buf[i] > 0) {
            j = floor((long double)x / buf[i]);
            LL pos = upper_bound(buf, buf+n, j) - buf;
            cnt += pos; 
        } else if(buf[i] < 0) {
            j = ceil((long double)x / buf[i]);
            LL pos = lower_bound(buf, buf+n, j) - buf;
            cnt += n - pos;
        } else {
            if(x >= 0) cnt += n;
        }
    }
    cnt /= 2;
    return cnt >= k;
}

void run_case() {
    cin >> n >> k;
    for(int i = 0; i < n; ++i) cin >> buf[i];
    sort(buf, buf+n);
    LL l = -(1LL<<60), r = 1LL<<60, ans, mid;
    while(l <= r) {
        mid = (l+r)>>1;
        if(check(mid)) {
            ans = mid;
            r = mid-1;
        } else
            l = mid+1;
    }
    cout << ans;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    //cout.setf(ios_base::showpoint);cout.precision(8);
    run_case();
    cout.flush();
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/GRedComeT/p/12322582.html
今日推荐