Problem p02774 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
#define WHOLE(v) (v).begin(), (v).end()
#define REV_WHOLE(v) (v).rbegin(), (v).rend()
using i64 = int64_t;
using namespace std;
template <class F> auto recursive(F f) {
  return [f](auto... a) { return f(f, a...); };
}
template <class I, class V = typename I::value_type>
V sum_up(const I &l, const I &r) {
  V v;
  for (I i = l; i != r; i++)
    v = i == l ? *i : v + *i;
  return v;
}
template <class I, class T = iterator_traits<I>> I operator+(I it, int n) {
  for (int i = 0; i < n; i++)
    it++;
  return it;
}
template <class I, class T = iterator_traits<I>> I operator-(I it, int n) {
  for (int i = 0; i < n; i++)
    it--;
  return it;
}
template <class T>
using rev_priority_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> using vector2d = vector<vector<T>>;
struct fixprec {
  int x;
  fixprec(int d) : x(d) {}
};
ostream &operator<<(ostream &o, fixprec f) {
  return o << fixed << setprecision(f.x);
}
void R_YESNO(bool p) { cout << (p ? "YES" : "NO") << endl; }
void R_YesNo(bool p) { cout << (p ? "Yes" : "No") << endl; }

/*!* [binsearch] *!*/
/*+* 二分探索 *+*/
// judge を満たすような下限を求める
// l:[X] 定義域外部の上限
// r:[X] 定義域外部の下限
// judge:[X -> bool] X を評価する関数
// lower:[bool] falseにすると代わりに上限を求める
// eps:[X] 終了距離

template <typename X>
X BinSearch(X l, X r, function<bool(X)> judge, bool lower = true, X eps = 1) {
  while (r - l > eps) {
    X m = (r + l) / 2;
    if (judge(m) == lower) {
      r = m;
    } else {
      l = m;
    }
  }
  return lower ? r : l;
}

// O(NlogNlogK) = O(N(logN)^2)
int main() {
  i64 N, K;
  cin >> N >> K;
  vector<i64> V(N);
  for (i64 &a : V)
    cin >> a;
  sort(WHOLE(V));
  i64 A[int(2e5)];
  for (int i = 0; i < N; i++)
    A[i] = V[i];
  i64 ans = BinSearch<i64>(-1.1e18, 1.1e18, [&](i64 X) -> bool {
    // X |-> M:積ペアのうちX以下のものの数
    i64 M = 0;
    // O(NlogN)
    for (int i = 0; i < N; i++) {
      // k : A[i] と積を取ってX以下になる限界
      int k = BinSearch<int>(
          -1, N, [&A, i, X](int j) -> bool { return A[i] * A[j] <= X; },
          A[i] < 0);
      if (A[i] < 0) {
        M += N - k;
      } else {
        M += k + 1;
      }
      // 自乗が含まれているなら削除
      if (A[i] * A[i] <= X)
        M--;
    }
    // ダブルカウンティングを解消
    return M >= 2 * K;
  });
  cout << ans << endl;
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
#define WHOLE(v) (v).begin(), (v).end()
#define REV_WHOLE(v) (v).rbegin(), (v).rend()
using i64 = int64_t;
using namespace std;
template <class F> auto recursive(F f) {
  return [f](auto... a) { return f(f, a...); };
}
template <class I, class V = typename I::value_type>
V sum_up(const I &l, const I &r) {
  V v;
  for (I i = l; i != r; i++)
    v = i == l ? *i : v + *i;
  return v;
}
template <class I, class T = iterator_traits<I>> I operator+(I it, int n) {
  for (int i = 0; i < n; i++)
    it++;
  return it;
}
template <class I, class T = iterator_traits<I>> I operator-(I it, int n) {
  for (int i = 0; i < n; i++)
    it--;
  return it;
}
template <class T>
using rev_priority_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> using vector2d = vector<vector<T>>;
struct fixprec {
  int x;
  fixprec(int d) : x(d) {}
};
ostream &operator<<(ostream &o, fixprec f) {
  return o << fixed << setprecision(f.x);
}
void R_YESNO(bool p) { cout << (p ? "YES" : "NO") << endl; }
void R_YesNo(bool p) { cout << (p ? "Yes" : "No") << endl; }

/*!* [binsearch] *!*/
/*+* 二分探索 *+*/
// judge を満たすような下限を求める
// l:[X] 定義域外部の上限
// r:[X] 定義域外部の下限
// judge:[X -> bool] X を評価する関数
// lower:[bool] falseにすると代わりに上限を求める
// eps:[X] 終了距離

template <typename X>
X BinSearch(X l, X r, function<bool(X)> judge, bool lower = true, X eps = 1) {
  while (r - l > eps) {
    X m = (r + l) / 2;
    if (judge(m) == lower) {
      r = m;
    } else {
      l = m;
    }
  }
  return lower ? r : l;
}

// O(NlogNlogK) = O(N(logN)^2)
int main() {
  i64 N, K;
  cin >> N >> K;
  vector<i64> V(N);
  for (i64 &a : V)
    cin >> a;
  sort(WHOLE(V));
  i64 A[int(2e5)];
  for (int i = 0; i < N; i++)
    A[i] = V[i];
  i64 ans = BinSearch<i64>(-1.1e18, 1.1e18, [&](i64 X) -> bool {
    // X |-> M:積ペアのうちX以下のものの数
    i64 M = 0;
    // O(NlogN)
    for (int i = 0; i < N; i++) {
      // k : A[i] と積を取ってX以下になる限界
      // int k = BinSearch<int>(-1, N, [&A, i, X](int j) -> bool {
      //     return A[i] * A[j] <= X;
      // }, A[i] < 0);
      int k = 0;
      {
        {
          {
            int l = -1, r = N, eps = 1;
            bool lower = A[i] < 0;
            while (r - l > eps) {
              int m = (r + l) / 2;
              if ((A[i] * A[m] <= X) == lower) {
                r = m;
              } else {
                l = m;
              }
            }
            k = lower ? r : l;
          }
        }
      }

      if (A[i] < 0) {
        M += N - k;
      } else {
        M += k + 1;
      }
      // 自乗が含まれているなら削除
      if (A[i] * A[i] <= X)
        M--;
    }
    // ダブルカウンティングを解消
    return M >= 2 * K;
  });
  cout << ans << endl;
  return 0;
}