Problem p02774 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll count_neg(vector<ll> &neg, vector<ll> &pos, ll x) {
  // x以下の組み合わせを数え上げる
  ll cnt = 0;
  for (const auto &val : pos) {
    ll ng = -1;
    ll ok = neg.size();
    auto isOK = [&](ll mid) { return val * neg[mid] > x; };
    while (abs(ok - ng) > 1) {
      ll mid = (ok + ng) / 2;
      if (isOK(mid))
        ok = mid;
      else
        ng = mid;
    }
    cnt += ng + 1;
  }
  return cnt;
}

void negative_routine(vector<ll> &neg, vector<ll> &pos, ll K) {
  ll right = 0;
  ll left = neg.front() * pos.back() - 1;
  while (left + 1 < right) {
    ll cand = (left + right) / 2;
    ll ret = count_neg(neg, pos, cand);
    // cand以下の個数がK個より大きければ　
    if (ret >= K) {
      right = cand;
    } else {
      left = cand;
    }
  }
  // x 以下の組み合わせがK個以上である　を始めてみたすxがright
  // x 以下の組み合わせが1個以上であるを　初めて満たすのは -12
  printf("%lld\n", right);
}

ll count_pos(vector<ll> &neg, vector<ll> &pos, ll x) {
  // x以下のものをカウントする
  ll cnt = 0;
  for (const auto &val : pos) {
    // ng側に val*pos <= xを集めたい
    ll ng = -1;
    ll ok = pos.size();
    auto isOK = [&](ll key) { return val * pos[key] > x; };
    while (abs(ok - ng) > 1) {
      ll mid = (ok + ng) / 2;
      if (isOK(mid))
        ok = mid;
      else
        ng = mid;
    }
    if (ng >= 0 && pos[ng] >= val)
      cnt -= 1;
    cnt += ng + 1;
  }

  for (const auto &val : neg) {
    ll ng = -1;
    ll ok = neg.size();
    auto isOK = [&](ll key) { return val * neg[key] <= x; };
    while (abs(ok - ng) > 1) {
      ll mid = (ok + ng) / 2;
      if (isOK(mid))
        ok = mid;
      else
        ng = mid;
    }
    if (ok < neg.size() && neg[ok] <= val)
      cnt -= 1;
    // okなものが存在して、val以下のモノがあったら重複が出ている　-3, -2,
    // -1のならびで neg[ok]が-2 valが-1ならと考えると
    //  ok は -2,-1で -1 含んでおり neg[ok]<= val = -1
    cnt += neg.size() - ok;
  }
  return cnt / 2;
}

void positive_routine(vector<ll> &neg, vector<ll> &pos, ll K) {
  ll cand2 = (neg.size() > 0) ? 0 : neg.front() * neg.front() + 1;
  ll cand1 = (pos.size() > 0) ? 0 : pos.back() * pos.back() + 1;
  ll right = max(cand1, cand2);
  ll left = 0;
  while (left + 1 < right) {
    ll cand = (left + right) / 2;
    ll ret = count_pos(neg, pos, cand);
    if (ret >= K) {
      right = cand;
    } else {
      left = cand;
    }
  }
  printf("%lld\n", right);
}

// Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You
// use the default template now. You can remove this line by using your custom
// template)
int main() {
  ll N, K;
  cin >> N >> K;

  vector<int> A(N);
  for (int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
  }
  sort(A.begin(), A.end());
  vector<ll> neg;
  vector<ll> zeros;
  vector<ll> pos;
  for (const auto &val : A) {
    if (val < 0)
      neg.push_back(val);
    else if (val == 0)
      zeros.push_back(0);
    else
      pos.push_back(val);
  }
  ll negative_count = neg.size() * pos.size();
  ll zero_count =
      zeros.size() * (N - zeros.size()) + (zeros.size() - 1) * zeros.size() / 2;
  if (K <= negative_count) {
    negative_routine(neg, pos, K);
  } else if (K <= negative_count + zero_count) {
    printf("0\n");
  } else {
    positive_routine(neg, pos, K - negative_count - zero_count);
  }

  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll count_neg(vector<ll> &neg, vector<ll> &pos, ll x) {
  // x以下の組み合わせを数え上げる
  ll cnt = 0;
  for (const auto &val : pos) {
    ll ng = -1;
    ll ok = neg.size();
    auto isOK = [&](ll mid) { return val * neg[mid] > x; };
    while (abs(ok - ng) > 1) {
      ll mid = (ok + ng) / 2;
      if (isOK(mid))
        ok = mid;
      else
        ng = mid;
    }
    cnt += ng + 1;
  }
  return cnt;
}

void negative_routine(vector<ll> &neg, vector<ll> &pos, ll K) {
  ll right = 0;
  ll left = neg.front() * pos.back() - 1;
  while (left + 1 < right) {
    ll cand = (left + right) / 2;
    ll ret = count_neg(neg, pos, cand);
    // cand以下の個数がK個より大きければ　
    if (ret >= K) {
      right = cand;
    } else {
      left = cand;
    }
  }
  // x 以下の組み合わせがK個以上である　を始めてみたすxがright
  // x 以下の組み合わせが1個以上であるを　初めて満たすのは -12
  printf("%lld\n", right);
}

ll count_pos(vector<ll> &neg, vector<ll> &pos, ll x) {
  // x以下のものをカウントする
  ll cnt = 0;
  for (const auto &val : pos) {
    // ng側に val*pos <= xを集めたい
    ll ng = -1;
    ll ok = pos.size();
    auto isOK = [&](ll key) { return val * pos[key] > x; };
    while (abs(ok - ng) > 1) {
      ll mid = (ok + ng) / 2;
      if (isOK(mid))
        ok = mid;
      else
        ng = mid;
    }
    if (ng >= 0 && pos[ng] >= val)
      cnt -= 1;
    cnt += ng + 1;
  }

  for (const auto &val : neg) {
    ll ng = -1;
    ll ok = neg.size();
    auto isOK = [&](ll key) { return val * neg[key] <= x; };
    while (abs(ok - ng) > 1) {
      ll mid = (ok + ng) / 2;
      if (isOK(mid))
        ok = mid;
      else
        ng = mid;
    }
    if (ok < neg.size() && neg[ok] <= val)
      cnt -= 1;
    // okなものが存在して、val以下のモノがあったら重複が出ている　-3, -2,
    // -1のならびで neg[ok]が-2 valが-1ならと考えると
    //  ok は -2,-1で -1 含んでおり neg[ok]<= val = -1
    cnt += neg.size() - ok;
  }
  return cnt / 2;
}

void positive_routine(vector<ll> &neg, vector<ll> &pos, ll K) {
  ll cand2 = (neg.size() > 0) ? neg.front() * neg.front() + 1 : 1;
  ll cand1 = (pos.size() > 0) ? pos.back() * pos.back() + 1 : 1;
  ll right = max(cand1, cand2);
  ll left = 0;
  while (left + 1 < right) {
    ll cand = (left + right) / 2;
    ll ret = count_pos(neg, pos, cand);
    if (ret >= K) {
      right = cand;
    } else {
      left = cand;
    }
  }
  printf("%lld\n", right);
}

// Generated by 1.1.6 https://github.com/kyuridenamida/atcoder-tools  (tips: You
// use the default template now. You can remove this line by using your custom
// template)
int main() {
  ll N, K;
  cin >> N >> K;

  vector<int> A(N);
  for (int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
  }
  sort(A.begin(), A.end());
  vector<ll> neg;
  vector<ll> zeros;
  vector<ll> pos;
  for (const auto &val : A) {
    if (val < 0)
      neg.push_back(val);
    else if (val == 0)
      zeros.push_back(0);
    else
      pos.push_back(val);
  }
  ll negative_count = neg.size() * pos.size();
  ll zero_count =
      zeros.size() * (N - zeros.size()) + (zeros.size() - 1) * zeros.size() / 2;
  if (K <= negative_count) {
    negative_routine(neg, pos, K);
  } else if (K <= negative_count + zero_count) {
    printf("0\n");
  } else {
    positive_routine(neg, pos, K - negative_count - zero_count);
  }

  return 0;
}