Problem p03332 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

using namespace std;

namespace {

template <int MOD> class IntMod {
  static_assert(0 < MOD and MOD <= numeric_limits<int>::max() / 2,
                "MOD out of range");

  int val;

public:
  IntMod() : val(0) {}

  IntMod(int64_t x) : val(static_cast<int>(x % MOD)) {
    if (val < 0)
      val += MOD;
  }

  IntMod &operator+=(const IntMod &x) {
    val += x.val;
    if (val >= MOD)
      val -= MOD;
    return *this;
  }

  IntMod operator+(const IntMod &x) const {
    IntMod res(*this);
    return res += x;
  }

  IntMod &operator-=(const IntMod &x) {
    val -= x.val;
    if (val < 0)
      val += MOD;
    return *this;
  }

  IntMod operator-(const IntMod &x) const {
    IntMod res(*this);
    return res -= x;
  }

  IntMod &operator*=(const IntMod &x) {
    val = static_cast<int>(static_cast<long long>(val) * x.val % MOD);
    return *this;
  }

  IntMod operator*(const IntMod &x) const {
    IntMod res(*this);
    return res *= x;
  }

  IntMod &operator/=(const IntMod &x) { return *this *= x.Inv(); }

  IntMod operator/(const IntMod &x) const {
    IntMod res(*this);
    return res /= x;
  }

  IntMod operator-() const {
    IntMod res(*this);
    if (res.val != 0)
      res.val = MOD - res.val;
    return res;
  }

  /**
   * if expon is negative returns 1
   */
  IntMod Power(int expon) const {
    IntMod ans(1), temp(*this);
    for (; expon > 0; expon >>= 1) {
      if (expon & 1)
        ans *= temp;
      temp *= temp;
    }
    return ans;
  }

  /**
   *  Undefined if this value is not coprime with MOD
   */
  IntMod Inv() const {
    int64_t a = MOD, b = val, nx = 1, x = 0;
    while (b != 0) {
      tie(nx, x) = make_pair(x - (a / b) * nx, nx);
      tie(a, b) = make_pair(b, a % b);
    }
    return IntMod(x);
  }

  explicit operator int() const { return val; }

  friend ostream &operator<<(ostream &out, const IntMod &x) {
    return out << x.val;
  }

  bool operator==(const IntMod &x) const { return val == x.val; }

  bool operator!=(const IntMod &x) const { return val != x.val; }
};

#define VEVE(i, a, b) for (ll i = a, __##i = b; i < __##i; ++i)
#define DYDY(i, a, b) for (ll i = a, __##i = b; i > __##i; --i)
#define RARA(x, seq) for (auto &x : seq)
#define SIZE(x) ((ll)(x.size()))
#define ALL(x) x.begin(), x.end()

typedef int64_t ll;
typedef double dd;
const ll MOD = 998244353;
typedef IntMod<MOD> Int;

/**
 * r*A + b*B + g*(A+B) = K
 */
void Solve(ll) {
  ll n, a, b, k;
  if (not(cin >> n >> a >> b >> k))
    return;
  vector<Int> fact(2 * n + 1), ifact(2 * n + 1);
  fact[0] = ifact[0] = 1;
  VEVE(i, 1, SIZE(fact)) {
    fact[i] = fact[i - 1] * i;
    ifact[i] = fact[i].Inv();
  }
  auto choose = [&](ll n, ll k) {
    //    if (k > n or n < 0)
    //      return Int();
    return fact[n] * ifact[k] * ifact[n - k];
  };
  vector<Int> choose_sum(n + 1);
  choose_sum[0] = choose(n, 0);
  VEVE(i, 1, n + 1) choose_sum[i] = choose_sum[i - 1] + choose(n, i);
  Int res;
  VEVE(red, 0, n + 1) {
    ll blue = k - red * a;
    if (blue < 0 or blue % b != 0)
      continue;
    blue /= b;
    //    Int now = 0;
    ////    DEBUG(red);
    //    // red + blue - g <= n
    //    // g >= (red + blue - n)
    //    VEVE(green, max(ll(0), red + blue - n), min(red, blue) + 1) {
    //      now += choose(n, green) * choose(n - green, red - green) * choose(n
    //      - red, blue - green);
    //    }
    /*
     * n!        (n-g)!         (n-r)!
     * ----      ------         -----------------
     * g! (n-g)! (r-g)! (n-r)!  (b-g)! (n-r-b+g)!
     */
    res += choose(n, red) * choose(n, blue);
  }
  cout << res << endl;
}

void Init() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
}
} // namespace

int32_t main() {
#ifdef AZN
  freopen("input.txt", "r", stdin);
#endif
  Init();
  ll tests = 11;
  VEVE(test, 1, tests + 1) Solve(test);
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>

using namespace std;

namespace {

template <int MOD> class IntMod {
  static_assert(0 < MOD and MOD <= numeric_limits<int>::max() / 2,
                "MOD out of range");

  int val;

public:
  IntMod() : val(0) {}

  IntMod(int64_t x) : val(static_cast<int>(x % MOD)) {
    if (val < 0)
      val += MOD;
  }

  IntMod &operator+=(const IntMod &x) {
    val += x.val;
    if (val >= MOD)
      val -= MOD;
    return *this;
  }

  IntMod operator+(const IntMod &x) const {
    IntMod res(*this);
    return res += x;
  }

  IntMod &operator-=(const IntMod &x) {
    val -= x.val;
    if (val < 0)
      val += MOD;
    return *this;
  }

  IntMod operator-(const IntMod &x) const {
    IntMod res(*this);
    return res -= x;
  }

  IntMod &operator*=(const IntMod &x) {
    val = static_cast<int>(static_cast<long long>(val) * x.val % MOD);
    return *this;
  }

  IntMod operator*(const IntMod &x) const {
    IntMod res(*this);
    return res *= x;
  }

  IntMod &operator/=(const IntMod &x) { return *this *= x.Inv(); }

  IntMod operator/(const IntMod &x) const {
    IntMod res(*this);
    return res /= x;
  }

  IntMod operator-() const {
    IntMod res(*this);
    if (res.val != 0)
      res.val = MOD - res.val;
    return res;
  }

  /**
   * if expon is negative returns 1
   */
  IntMod Power(int expon) const {
    IntMod ans(1), temp(*this);
    for (; expon > 0; expon >>= 1) {
      if (expon & 1)
        ans *= temp;
      temp *= temp;
    }
    return ans;
  }

  /**
   *  Undefined if this value is not coprime with MOD
   */
  IntMod Inv() const {
    int64_t a = MOD, b = val, nx = 1, x = 0;
    while (b != 0) {
      tie(nx, x) = make_pair(x - (a / b) * nx, nx);
      tie(a, b) = make_pair(b, a % b);
    }
    return IntMod(x);
  }

  explicit operator int() const { return val; }

  friend ostream &operator<<(ostream &out, const IntMod &x) {
    return out << x.val;
  }

  bool operator==(const IntMod &x) const { return val == x.val; }

  bool operator!=(const IntMod &x) const { return val != x.val; }
};

#define VEVE(i, a, b) for (ll i = a, __##i = b; i < __##i; ++i)
#define DYDY(i, a, b) for (ll i = a, __##i = b; i > __##i; --i)
#define RARA(x, seq) for (auto &x : seq)
#define SIZE(x) ((ll)(x.size()))
#define ALL(x) x.begin(), x.end()

typedef int64_t ll;
typedef double dd;
const ll MOD = 998244353;
typedef IntMod<MOD> Int;

/**
 * r*A + b*B + g*(A+B) = K
 */
void Solve(ll) {
  ll n, a, b, k;
  if (not(cin >> n >> a >> b >> k))
    return;
  vector<Int> fact(2 * n + 1), ifact(2 * n + 1);
  fact[0] = ifact[0] = 1;
  VEVE(i, 1, SIZE(fact)) {
    fact[i] = fact[i - 1] * i;
    ifact[i] = fact[i].Inv();
  }
  auto choose = [&](ll n, ll k) {
    if (k > n or n < 0)
      return Int();
    return fact[n] * ifact[k] * ifact[n - k];
  };
  vector<Int> choose_sum(n + 1);
  choose_sum[0] = choose(n, 0);
  VEVE(i, 1, n + 1) choose_sum[i] = choose_sum[i - 1] + choose(n, i);
  Int res;
  VEVE(red, 0, n + 1) {
    ll blue = k - red * a;
    if (blue < 0 or blue % b != 0)
      continue;
    blue /= b;
    //    Int now = 0;
    ////    DEBUG(red);
    //    // red + blue - g <= n
    //    // g >= (red + blue - n)
    //    VEVE(green, max(ll(0), red + blue - n), min(red, blue) + 1) {
    //      now += choose(n, green) * choose(n - green, red - green) * choose(n
    //      - red, blue - green);
    //    }
    /*
     * n!        (n-g)!         (n-r)!
     * ----      ------         -----------------
     * g! (n-g)! (r-g)! (n-r)!  (b-g)! (n-r-b+g)!
     */
    res += choose(n, red) * choose(n, blue);
  }
  cout << res << endl;
}

void Init() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
}
} // namespace

int32_t main() {
#ifdef AZN
  freopen("input.txt", "r", stdin);
#endif
  Init();
  ll tests = 11;
  VEVE(test, 1, tests + 1) Solve(test);
  return 0;
}