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

#include "algorithm"
#include "bitset"
#include "cassert"
#include "climits"
#include "cmath"
#include "cstdio"
#include "ctime"
#include "functional"
#include "iomanip"
#include "iostream"
#include "list"
#include "map"
#include "numeric"
#include "queue"
#include "random"
#include "set"
#include "stack"
#include "string"

using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, ll> Pll;
#define rep(begin, i, end) for (int i = begin; i < (int)(end); i++)
#define all(v) v.begin(), v.end()
const int MOD = 1000000007;

ll MODpow(ll a, ll b) {
  if (b == 0) {
    return 1;
  } else if (b % 2 == 0) {
    return (MODpow(a, b / 2) * MODpow(a, b / 2)) % MOD;
  } else {
    return (a * MODpow(a, b - 1)) % MOD;
  }
}

int main() {
  ll N, K;
  cin >> N >> K;
  vector<Pll> A(N);
  ll pos = 0;
  rep(0, i, N) {
    ll a, b;
    cin >> a;
    if (a < 0) {
      a *= -1;
      b = -1;
    } else {
      pos = 1;
      b = 1;
    }

    A.at(i) = make_pair(a, b);
  }

  sort(all(A));

  // N = Kの自明な場合
  if (N == K) {
    ll ans = 1;
    rep(0, i, N) {
      ans *= (A.at(i).first * A.at(i).second + MOD);
      ans %= MOD;
    }

    cout << ans << endl;
    return 0;
  }

  // 最大値が負になるとき
  if ((pos == 0) && (K % 2 != 0)) {
    // 絶対値が小さい順に掛け算していく
    ll ans = 1;
    rep(0, i, K) {
      ans *= (A.at(i).first * A.at(i).second + MOD);
      ans %= MOD;
    }

    cout << ans << endl;
  }
  // 最大値が正になるとき
  else {
    // まずは貪欲に絶対値が大きい順に掛け算してみる
    reverse(all(A));
    ll ans = 1;
    ll c_n = 0; // 負の数を何回かけたのか
    rep(0, i, K) {
      ans *= (A.at(i).first * A.at(i).second + MOD);
      ans %= MOD;
      if (A.at(i).second == -1) {
        c_n++;
      }
    }

    // 最終的に正の数になるならばそれが答えになる
    if (c_n % 2 == 0) {
      cout << ans << endl;
    }
    // そうでない場合、最大値の候補は(高々)二つ
    else {
      // (K個の貪欲積のなかで)絶対値が一番小さい正の数、負の数の添字を求める
      ll old_p = -1,
         old_n =
             -1; // これは(どちらかが)見つからない可能性があるのでフラグの役割も兼ねて-1で初期化
      rep(0, i, K) {
        if (A.at(i).second == 1) {
          old_p = i;
        } else {
          old_n = i;
        }
      }
      // 余った数字の中で絶対値が最も大きい正の数、負の数を求める
      ll new_p = -1,
         new_n =
             -1; // これは(どちらかが)見つからない可能性があるのでフラグの役割も兼ねて-1で初期化
      for (ll i = N - 1; i >= K; i--) {
        if (A.at(i).second == 1) {
          new_p = i;
        } else {
          new_n = i;
        }
      }

      // どちらか片方の交換しか実現できない場合
      if ((old_n == -1 || new_p == -1)) {
        // 正の数を取り除いて負の数を新たに掛け算したものが最大
        ans *= MODpow((A.at(old_p).first * A.at(old_p).second + MOD) % MOD,
                      MOD - 2);
        ans %= MOD;
        ans *= (A.at(new_n).first * A.at(new_n).second + MOD);
        ans %= MOD;
      } else if ((old_p == -1 || new_n == -1)) {
        // 負の数を取り除いて正の数を新たに掛け算したものが最大
        ans *= MODpow((A.at(old_n).first * A.at(old_n).second + MOD) % MOD,
                      MOD - 2);
        ans %= MOD;
        ans *= (A.at(new_p).first * A.at(new_p).second + MOD);
        ans %= MOD;
      }
      // 最大値の候補が二つあるとき
      else {

        // どちらが最大値になるのかを判定する変数
        ll num1 = 0, num2 = 0;

        // その変数が作れるならば計算をする
        if ((new_n != -1) && (old_n != -1)) {
          num1 = A.at(new_n).first * A.at(old_n).first;
        }
        if ((new_p != -1) && (old_p != -1)) {
          num2 = A.at(new_p).first * A.at(old_p).first;
        }

        if (num1 > num2) {
          // 正の数を取り除いて負の数を新たに掛け算したものが最大
          ans *= MODpow((A.at(old_p).first * A.at(old_p).second + MOD) % MOD,
                        MOD - 2);
          ans %= MOD;
          ans *= (A.at(new_n).first * A.at(new_n).second + MOD);
          ans %= MOD;
        } else {
          // 負の数を取り除いて正の数を新たに掛け算したものが最大
          ans *= MODpow((A.at(old_n).first * A.at(old_n).second + MOD) % MOD,
                        MOD - 2);
          ans %= MOD;
          ans *= (A.at(new_p).first * A.at(new_p).second + MOD);
          ans %= MOD;
        }
      }

      cout << ans << endl;
    }
  }
}

Error: 0

Fixed submission:

#include "algorithm"
#include "bitset"
#include "cassert"
#include "climits"
#include "cmath"
#include "cstdio"
#include "ctime"
#include "functional"
#include "iomanip"
#include "iostream"
#include "list"
#include "map"
#include "numeric"
#include "queue"
#include "random"
#include "set"
#include "stack"
#include "string"

using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, ll> Pll;
#define rep(begin, i, end) for (int i = begin; i < (int)(end); i++)
#define all(v) v.begin(), v.end()
const int MOD = 1000000007;

ll MODpow(ll a, ll b) {
  if (b == 0) {
    return 1;
  } else if (b % 2 == 0) {
    return (MODpow(a, b / 2) * MODpow(a, b / 2)) % MOD;
  } else {
    return (a * MODpow(a, b - 1)) % MOD;
  }
}

int main() {
  ll N, K;
  cin >> N >> K;
  vector<Pll> A(N);
  ll pos = 0;
  rep(0, i, N) {
    ll a, b;
    cin >> a;
    if (a < 0) {
      a *= -1;
      b = -1;
    } else {
      pos = 1;
      b = 1;
    }

    A.at(i) = make_pair(a, b);
  }

  sort(all(A));

  // N = Kの自明な場合
  if (N == K) {
    ll ans = 1;
    rep(0, i, N) {
      ans *= (A.at(i).first * A.at(i).second + MOD);
      ans %= MOD;
    }

    cout << ans << endl;
    return 0;
  }

  // 最大値が負になるとき
  if ((pos == 0) && (K % 2 != 0)) {
    // 絶対値が小さい順に掛け算していく
    ll ans = 1;
    rep(0, i, K) {
      ans *= (A.at(i).first * A.at(i).second + MOD);
      ans %= MOD;
    }

    cout << ans << endl;
  }
  // 最大値が正になるとき
  else {
    // まずは貪欲に絶対値が大きい順に掛け算してみる
    reverse(all(A));
    ll ans = 1;
    ll c_n = 0; // 負の数を何回かけたのか
    rep(0, i, K) {
      ans *= (A.at(i).first * A.at(i).second + MOD);
      ans %= MOD;
      if (A.at(i).second == -1) {
        c_n++;
      }
    }

    // 最終的に正の数になるならばそれが答えになる
    if (c_n % 2 == 0) {
      cout << ans << endl;
    }
    // そうでない場合、最大値の候補は(高々)二つ
    else {
      // (K個の貪欲積のなかで)絶対値が一番小さい正の数、負の数の添字を求める
      ll old_p = -1,
         old_n =
             -1; // これは(どちらかが)見つからない可能性があるのでフラグの役割も兼ねて-1で初期化
      rep(0, i, K) {
        if (A.at(i).second == 1) {
          old_p = i;
        } else {
          old_n = i;
        }
      }
      // 余った数字の中で絶対値が最も大きい正の数、負の数を求める
      ll new_p = -1,
         new_n =
             -1; // これは(どちらかが)見つからない可能性があるのでフラグの役割も兼ねて-1で初期化
      for (ll i = N - 1; i >= K; i--) {
        if (A.at(i).second == 1) {
          new_p = i;
        } else {
          new_n = i;
        }
      }

      // どちらが最大値になるのかを判定する変数
      ll num1 = 0, num2 = 0;

      // 値の交換が可能なら最大値の候補となる
      if ((new_n != -1) && (old_n != -1)) {
        num1 = A.at(new_n).first * A.at(old_n).first;
      }
      if ((new_p != -1) && (old_p != -1)) {
        num2 = A.at(new_p).first * A.at(old_p).first;
      }

      if (num1 > num2) {
        // 正の数を取り除いて負の数を新たに掛け算したものが最大
        ans *= MODpow((A.at(old_p).first * A.at(old_p).second + MOD) % MOD,
                      MOD - 2);
        ans %= MOD;
        ans *= (A.at(new_n).first * A.at(new_n).second + MOD);
        ans %= MOD;
      } else {
        // 負の数を取り除いて正の数を新たに掛け算したものが最大
        ans *= MODpow((A.at(old_n).first * A.at(old_n).second + MOD) % MOD,
                      MOD - 2);
        ans %= MOD;
        ans *= (A.at(new_p).first * A.at(new_p).second + MOD);
        ans %= MOD;
      }

      cout << ans << endl;
    }
  }
}