Problem p02616 (C++) — buggy submission, verdict: Runtime Error

/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
*$* WRITER:kakitamasziru/OxOmisosiru *$*
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/
#ifdef LOCAL_JUDGE
#define _GLIBCXX_DEBUG
#endif
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <cstdint>   // int64_t, int*_t
#include <iomanip>
#include <iostream> // cout, endl, cin
#include <limits>   //setprecision
#include <string>   // string, to_string, stoi
#include <tuple>    // tuple, make_tuple
#include <utility>  // pair, make_pair
#include <vector>   // vector
// #include <cstdio> // printf
#include <map>   // map
#include <queue> // queue, priority_queue
#include <set>   // set
// #include <unordered_set> //unordered_set
#include <bitset> // bitset
#include <cmath>  //abs,,,
#include <deque>  // deque
#include <math.h> //pow,,,
#include <stack>  // stack
#define endl "\\n";
using namespace std;

const long long INF = 100100100100100;
const int MOD = 1000000007;
const int inf = 1001001001;
typedef pair<int, int> P;

// Solve N^M. This, mod_pow use Iterative Square Method.
long long mod_pow(long long N, long long M) {
  if (M == 0)
    return 1;
  long long res = mod_pow((N * N) % MOD, M / 2);
  // 最下位ビット(*N)が1の時は単独でNをかける
  if (M & 1)
    res = (res * N) % MOD;

  return res %= MOD;
}

long long gcd(long long a, long long b) {
  if (b == 0)
    return a;
  else
    return gcd(b, a % b);
}
long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }

priority_queue<long long> PQ_nega;
priority_queue<long long, vector<long long>, greater<long long>> PQ_posi;
priority_queue<long long, vector<long long>, greater<long long>>
    PQ_nega_nonchosen;
priority_queue<long long> PQ_posi_nonchosen;

int main() {
  ios::sync_with_stdio(false);
  std::cin.tie(nullptr);

  int N, K;
  cin >> N >> K;
  vector<pair<long long, int>> retu(N);
  vector<bool> posi_nega(N);
  bool allNega = true;
  for (int i = 0; i < N; i++) {
    cin >> retu.at(i).first;
    if (retu.at(i).first >= 0) {
      posi_nega.at(i) = true;
      allNega = false;
    } else {
      posi_nega.at(i) = false;
    }
    retu.at(i).first = abs(retu.at(i).first - 0);
    retu.at(i).second = i;
  }
  sort(retu.begin(), retu.end(), greater<pair<long long, int>>());
  // 絶対値大きい順にK個取って正だったらそれが答え
  int negaCount = 0;
  for (int i = 0; i < K; i++) {
    if (!posi_nega.at(retu.at(i).second))
      negaCount++;
  }
  if (negaCount % 2 == 0) {
    long long ans = 1;
    for (int i = 0; i < K; i++) {
      ans *= retu.at(i).first;
      ans %= MOD;
    }
    cout << ans << endl;
    return 0;
  }
  // 全部負でK個取っても負だったら、絶対値が小さい方からK個取るのが良い
  if (allNega) {
    long long ans = 1;
    for (int i = N - 1; i >= N - K; i--) {
      ans *= (retu.at(i).first * -1);
      ans %= MOD;
      if (ans < 0)
        ans += MOD;
    }
    cout << ans << endl;
    return 0;
  }

  // 後の処理の影響でN == Kの場合を先に処理します…許してくれ…
  if (N == K) {
    long long ans = 1;
    for (int i = 0; i < N; i++) {
      if (posi_nega.at(retu.at(i).second))
        ans *= retu.at(i).first;
      else
        ans *= retu.at(i).first * -1;
      ans %= MOD;
      if (ans < 0)
        ans += MOD;
    }
    cout << ans << endl;
    return 0;
  }

  // 残ったのは愚直にK個取ると負になってしまう場合
  // とりあえずK個取ってから、マイナス→プラスか、プラス→マイナスを一個だけする
  // PQ_nega,PQ_posiはK個選んだ時に選ばれた負と正

  for (int i = 0; i < N; i++) {
    if (posi_nega.at(retu.at(i).second) && i < K)
      PQ_posi.push(retu.at(i).first);
    if (!posi_nega.at(retu.at(i).second) && i < K)
      PQ_nega.push(retu.at(i).first * -1);
    if (posi_nega.at(retu.at(i).second) && i >= K)
      PQ_posi_nonchosen.push(retu.at(i).first);
    if (!posi_nega.at(retu.at(i).second) && i >= K)
      PQ_nega_nonchosen.push(retu.at(i).first * -1);
  }
  // 負しか選ばれなかった時は、絶対値小さいやつを選ばれてない中で正の絶対値大きいやつにする
  if (PQ_posi.empty()) {
    PQ_nega.pop();
    long long ans = 1;
    for (int i = 0; i < PQ_nega.size(); i += 0) {
      ans *= PQ_nega.top() * -1;
      PQ_nega.pop();
      ans %= MOD;
      if (ans < 0)
        ans += MOD;
    }
    ans *= PQ_posi_nonchosen.top();
    ans %= MOD;
    cout << ans << endl;
    return 0;
  }

  // 負も正も選ばれたときは、だるい
  // 負→正、正→負のどちらが得かを割合で考えて、頑張る
  long double maxiNega = PQ_nega.top() * -1;
  long double miniPosi = PQ_posi.top();
  long double nextNega;
  if (PQ_nega_nonchosen.empty()) {
    nextNega = -1;
  } else {
    nextNega = PQ_nega_nonchosen.top() * -1;
  }
  long double nextPosi;
  if (PQ_posi_nonchosen.empty()) {
    nextPosi = -1;
  } else {
    nextPosi = PQ_posi_nonchosen.top();
  }
  // cout << maxiNega << " " << miniPosi << " " << nextNega << " " << nextPosi
  // << endl;

  /*
  nextPosi/maxiNega < nextNega/miniPosi
  = nextPosi*miniPosi < maxiNega*nextNega
  */
  long double fromNegaToPosi = nextPosi * miniPosi;
  long double fromPosiToNega = maxiNega * nextNega;
  if (fromNegaToPosi < fromPosiToNega) {
    PQ_posi.pop();
    if (nextNega == -1)
      nextNega = 1;
    PQ_nega.push(nextNega * -1);
  } else {
    PQ_nega.pop();
    if (nextPosi == -1)
      nextPosi = 1;
    PQ_posi.push(nextPosi);
  }
  // 答えの計算
  long long ans = 1;
  for (int i = 0; i < PQ_nega.size(); i += 0) {
    ans *= PQ_nega.top() * -1;
    PQ_nega.pop();
    ans %= MOD;
    if (ans < 0)
      ans += MOD;
  }
  for (int i = 0; i < PQ_posi.size(); i += 0) {
    ans *= PQ_posi.top();
    PQ_posi.pop();
    ans %= MOD;
  }
  cout << ans << endl;
}

Error: 0

Fixed submission:

/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
*$* WRITER:kakitamasziru/OxOmisosiru *$*
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/
#ifdef LOCAL_JUDGE
#define _GLIBCXX_DEBUG
#endif
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <cstdint>   // int64_t, int*_t
#include <iomanip>
#include <iostream> // cout, endl, cin
#include <limits>   //setprecision
#include <string>   // string, to_string, stoi
#include <tuple>    // tuple, make_tuple
#include <utility>  // pair, make_pair
#include <vector>   // vector
// #include <cstdio> // printf
#include <map>   // map
#include <queue> // queue, priority_queue
#include <set>   // set
// #include <unordered_set> //unordered_set
#include <bitset> // bitset
#include <cmath>  //abs,,,
#include <deque>  // deque
#include <math.h> //pow,,,
#include <stack>  // stack
#define endl "\\n";
using namespace std;

const long long INF = 100100100100100;
const int MOD = 1000000007;
const int inf = 1001001001;
typedef pair<int, int> P;

// Solve N^M. This, mod_pow use Iterative Square Method.
long long mod_pow(long long N, long long M) {
  if (M == 0)
    return 1;
  long long res = mod_pow((N * N) % MOD, M / 2);
  // 最下位ビット(*N)が1の時は単独でNをかける
  if (M & 1)
    res = (res * N) % MOD;

  return res %= MOD;
}

long long gcd(long long a, long long b) {
  if (b == 0)
    return a;
  else
    return gcd(b, a % b);
}
long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }

priority_queue<long long> PQ_nega;
priority_queue<long long, vector<long long>, greater<long long>> PQ_posi;
priority_queue<long long, vector<long long>, greater<long long>>
    PQ_nega_nonchosen;
priority_queue<long long> PQ_posi_nonchosen;

int main() {
  ios::sync_with_stdio(false);
  std::cin.tie(nullptr);

  int N, K;
  cin >> N >> K;
  vector<pair<long long, int>> retu(N);
  vector<bool> posi_nega(N);
  bool allNega = true;
  for (int i = 0; i < N; i++) {
    cin >> retu.at(i).first;
    if (retu.at(i).first >= 0) {
      posi_nega.at(i) = true;
      allNega = false;
    } else {
      posi_nega.at(i) = false;
    }
    retu.at(i).first = abs(retu.at(i).first - 0);
    retu.at(i).second = i;
  }
  sort(retu.begin(), retu.end(), greater<pair<long long, int>>());
  // 絶対値大きい順にK個取って正だったらそれが答え
  int negaCount = 0;
  for (int i = 0; i < K; i++) {
    if (!posi_nega.at(retu.at(i).second))
      negaCount++;
  }
  if (negaCount % 2 == 0) {
    long long ans = 1;
    for (int i = 0; i < K; i++) {
      ans *= retu.at(i).first;
      ans %= MOD;
    }
    cout << ans << endl;
    return 0;
  }
  // 全部負でK個取っても負だったら、絶対値が小さい方からK個取るのが良い
  if (allNega) {
    long long ans = 1;
    for (int i = N - 1; i >= N - K; i--) {
      ans *= (retu.at(i).first * -1);
      ans %= MOD;
      if (ans < 0)
        ans += MOD;
    }
    cout << ans << endl;
    return 0;
  }

  // 残ったのは愚直にK個取ると負になってしまう場合
  // とりあえずK個取ってから、マイナス→プラスか、プラス→マイナスを一個だけする
  // PQ_nega,PQ_posiはK個選んだ時に選ばれた負と正

  for (int i = 0; i < N; i++) {
    if (posi_nega.at(retu.at(i).second) && i < K)
      PQ_posi.push(retu.at(i).first);
    if (!posi_nega.at(retu.at(i).second) && i < K)
      PQ_nega.push(retu.at(i).first * -1);
    if (posi_nega.at(retu.at(i).second) && i >= K)
      PQ_posi_nonchosen.push(retu.at(i).first);
    if (!posi_nega.at(retu.at(i).second) && i >= K)
      PQ_nega_nonchosen.push(retu.at(i).first * -1);
  }
  // 負しか選ばれなかった時は、絶対値小さいやつを選ばれてない中で正の絶対値大きいやつにする
  if (PQ_posi.empty()) {
    PQ_nega.pop();
    long long ans = 1;
    for (int i = 0; i < PQ_nega.size(); i += 0) {
      ans *= PQ_nega.top() * -1;
      PQ_nega.pop();
      ans %= MOD;
      if (ans < 0)
        ans += MOD;
    }
    ans *= PQ_posi_nonchosen.top();
    ans %= MOD;
    cout << ans << endl;
    return 0;
  }

  // 負も正も選ばれたときは、だるい
  // 負→正、正→負のどちらが得かを割合で考えて、頑張る
  long double maxiNega = PQ_nega.top() * -1;
  long double miniPosi = PQ_posi.top();
  long double nextNega = PQ_nega_nonchosen.top() * -1;
  long double nextPosi = PQ_posi_nonchosen.top();
  // cout << maxiNega << " " << miniPosi << " " << nextNega << " " << nextPosi
  // << endl;

  long double fromNegaToPosi = nextPosi / maxiNega;
  long double fromPosiToNega = nextNega / miniPosi;
  if (fromNegaToPosi < fromPosiToNega) {
    PQ_posi.pop();
    PQ_nega.push(nextNega * -1);
  } else {
    PQ_nega.pop();
    PQ_posi.push(nextPosi);
  }
  // 答えの計算
  long long ans = 1;
  for (int i = 0; i < PQ_nega.size(); i += 0) {
    ans *= PQ_nega.top() * -1;
    PQ_nega.pop();
    ans %= MOD;
    if (ans < 0)
      ans += MOD;
  }
  for (int i = 0; i < PQ_posi.size(); i += 0) {
    ans *= PQ_posi.top();
    PQ_posi.pop();
    ans %= MOD;
  }
  cout << ans << endl;
}