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

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
using ll = long long;

ll MOD = 1e9 + 7;
ll MUL(ll x, ll y) {
  if (x < 0)
    x += MOD;
  if (y < 0)
    y += MOD;
  assert(0 <= x && x < MOD);
  assert(0 <= y && y < MOD);
  return (x * y) % MOD;
}
ll POW(ll b, ll e) {
  assert(0 <= b && b < MOD);
  assert(0 <= e && e < MOD);
  if (e == 0) {
    return 1LL;
  } else if (e % 2 == 0) {
    return POW(MUL(b, b), e / 2);
  } else {
    return MUL(b, POW(b, e - 1));
  }
}
ll INV(ll x) {
  if (x < 0) {
    x += MOD;
  }
  assert(0 <= x && x < MOD);
  return POW(x, MOD - 2);
}
ll DIV(ll x, ll y) {
  if (x < 0) {
    x += MOD;
  }
  if (y < 0) {
    y += MOD;
  }
  assert(0 <= x && x < MOD);
  assert(0 <= y && y < MOD);
  return MUL(x, INV(y));
}

int main() {
  ll n, k;
  cin >> n >> k;
  assert(1 <= k && k <= n);
  vector<ll> A(n, 0);
  bool all_neg = true;
  for (ll i = 0; i < n; i++) {
    cin >> A[i];
    if (A[i] > 0) {
      all_neg = false;
    }
  }
  sort(A.begin(), A.end(), [](ll a, ll b) { return abs(a) > abs(b); });
  /*for(ll x : A) {
    cerr << x << " ";
  }
  cerr << endl;*/

  bool neg = false;
  ll ans = 1;
  ll last_neg = -1;
  ll last_pos = -1;
  for (ll i = 0; i < k; i++) {
    ans = MUL(ans, A[i]);
    if (A[i] < 0) {
      last_neg = i;
      neg = !neg;
    } else {
      last_pos = i;
    }
  }
  if (k == n) {
    // Special case: K=N. Then we are forced to take everything
    cout << ans << endl;
  } else if (!neg) {
    // If we already have a non-negative answer by multiplying everything with
    // the largest absolute value, this is the answer
    cout << ans << endl;
  } else if (k % 2 == 1 && all_neg) {
    // Special case if K is odd and all elements are negative
    // Then we want the *minimum* possible product
    ans = 1;
    for (ll i = 0; i < k; i++) {
      ans = MUL(ans, A[n - 1 - i]);
    }
    cout << ans << endl;
  } else {
    // We need to swap out a negative with a positive or a positive with a
    // negative We should swap out the last negative/positive (before K) with
    // the first negative/positive (after K) Should we swap N->P or P->N? If we
    // swap N->P we lose N and gain P (i.e. we gain P/N) If we swap P->N we lose
    // P and gain N (i.e. we gain N/P) So compare next_pos/last_neg vs.
    // next_neg/last_pos Cross-multiply: compare next_pos*last_pos vs.
    // next_neg*last_neg
    ll next_pos = -1;
    ll next_neg = -1;
    for (ll i = k; i < n; i++) {
      if (A[i] <= 0 && next_neg == -1) {
        next_neg = i;
      }
      if (A[i] >= 0 && next_pos == -1) {
        next_pos = i;
      }
    }
    /*for(ll x : A) {
      cout << x << " ";
    }
    cout << endl;
    cout << last_pos << " " << next_neg << " " << last_neg << " " << next_pos <<
    " " << (A[next_pos]*A[last_pos]) << " " << (A[next_neg]*A[last_neg]) <<
    endl;*/
    assert((last_pos >= 0 && next_neg >= 0) ||
           (last_neg >= 0 && next_pos >= 0));
    if ((last_neg >= 0 && last_pos >= 0 && next_pos >= 0 && next_neg >= 0 &&
         A[next_pos] * A[last_pos] < A[next_neg] * A[last_neg]) ||
        (last_pos >= 0 && next_neg >= 0 &&
         (last_neg == -1 || next_pos == -1))) {
      assert(last_pos >= 0 && next_neg >= 0);
      ans = DIV(ans, A[last_pos]);
      ans = MUL(ans, A[next_neg]);
    } else {
      assert(last_neg >= 0 && next_pos >= 0);
      ans = DIV(ans, A[last_neg]);
      ans = MUL(ans, A[next_pos]);
    }
    cout << ans << endl;
  }
}


Error: 0

Fixed submission:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
using ll = long long;

ll MOD = 1e9 + 7;
ll MUL(ll x, ll y) {
  if (x < 0)
    x += MOD;
  if (y < 0)
    y += MOD;
  assert(0 <= x && x < MOD);
  assert(0 <= y && y < MOD);
  return (x * y) % MOD;
}
ll POW(ll b, ll e) {
  assert(0 <= b && b < MOD);
  assert(0 <= e && e < MOD);
  if (e == 0) {
    return 1LL;
  } else if (e % 2 == 0) {
    return POW(MUL(b, b), e / 2);
  } else {
    return MUL(b, POW(b, e - 1));
  }
}
ll INV(ll x) {
  if (x < 0) {
    x += MOD;
  }
  assert(0 <= x && x < MOD);
  return POW(x, MOD - 2);
}
ll DIV(ll x, ll y) {
  if (x < 0) {
    x += MOD;
  }
  if (y < 0) {
    y += MOD;
  }
  assert(0 <= x && x < MOD);
  assert(0 <= y && y < MOD);
  return MUL(x, INV(y));
}

int main() {
  ll n, k;
  cin >> n >> k;
  vector<ll> A(n, 0);
  bool all_neg = true;
  for (ll i = 0; i < n; i++) {
    cin >> A[i];
    if (A[i] > 0) {
      all_neg = false;
    }
  }
  sort(A.begin(), A.end(), [](ll a, ll b) { return abs(a) > abs(b); });
  bool neg = false;
  ll ans = 1;
  ll last_neg = -1;
  ll last_pos = -1;
  for (ll i = 0; i < k; i++) {
    ans = MUL(ans, A[i]);
    if (A[i] < 0) {
      last_neg = i;
      neg = !neg;
    } else {
      last_pos = i;
    }
  }
  if (k == n) {
    // Special case: K=N. Then we are forced to take everything
    cout << ans << endl;
  } else if (!neg) {
    // If we already have a non-negative answer by multiplying everything with
    // the largest absolute value, this is the answer
    cout << ans << endl;
  } else if (k % 2 == 1 && all_neg) {
    // Special case if K is odd and all elements are negative
    // Then we want the *minimum* possible sum
    ans = 1;
    for (ll i = 0; i < k; i++) {
      ans = MUL(ans, A[n - 1 - i]);
    }
    cout << ans << endl;
  } else {
    // We need to swap out a negative with a positive or a positive with a
    // negative We should swap out the last negative/positive (before K) with
    // the first negative/positive (after K) Should we swap N->P or P->N? If we
    // swap N->P we lose N and gain P (i.e. we gain P/N) If we swap P->N we lose
    // P and gain N (i.e. we gain N/P) So compare next_pos/last_neg vs.
    // next_neg/last_pos Cross-multiply: compare next_pos*last_pos vs.
    // next_neg*last_neg
    ll next_pos = -1;
    ll next_neg = -1;
    for (ll i = k; i < n; i++) {
      if (A[i] < 0 && next_neg == -1) {
        next_neg = i;
      }
      if (A[i] > 0 && next_pos == -1) {
        next_pos = i;
      }
    }
    if ((last_neg >= 0 && last_pos >= 0 && next_pos >= 0 && next_neg >= 0 &&
         A[next_pos] * A[last_pos] < A[next_neg] * A[last_neg]) ||
        (last_pos >= 0 && next_neg >= 0)) {
      assert(last_pos >= 0 && next_neg >= 0);
      ans = DIV(ans, A[last_pos]);
      ans = MUL(ans, A[next_neg]);
    } else {
      assert(last_neg >= 0 && next_pos >= 0);
      ans = DIV(ans, A[last_neg]);
      ans = MUL(ans, A[next_pos]);
    }
    cout << ans << endl;
  }
}