Problem p03332 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

using namespace std;
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;

#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define FOR(i, a, b) for (int i = (a); i < (int)(b); ++i)
#define ALL(c) (c).begin(), (c).end()
#define SIZE(v) ((int)v.size())

#define pb push_back
#define mp make_pair
#define mt make_tuple

ll MOD = 998244353;

// ll gcd(ll a, ll b)
// {
//     while(1)
//     {
//         if (a == 0) return b;
//         b %= a;
//         if (b == 0) return a;
//         a %= b;
//     }
// }

ll modPow(ll x, ll y) {
  ll r = 1, a = x;
  while (y > 0) {
    if ((y & 1) == 1) {
      r = (r * a) % MOD;
    }
    a = (a * a) % MOD;
    y /= 2;
  }

  return r;
}
// Modular multiplicative inverse through Fermat's little theorem:
// フェルマーの小定理より, a^-1 ≡ a^(p-2) (mod p) というのを使うらしい
// ただし、pが素数の時しか成り立たない
ll modInverse(ll x) { return modPow(x, MOD - 2); }

// Modular division x / y, find modular multiplicative inverse of y
// and multiply by x.
ll modDivision(ll p, ll q) { return (p * modInverse(q)) % MOD; }

// Binomial coifficient C(n,k) in O(k) time.
void makeCTable(ll n, ll k, vector<ll> &table) {
  if (k > n) {
    return;
  }
  ll p = 1, q = 1;
  table[0] = 1;
  for (ll i = 1; i <= k; i++) {
    q = (q * i) % MOD;
    p = (p * (n - i + 1)) % MOD;
    table[i] = modDivision(p, q);
    // if (i % 1000 == 0) {
    //     cerr << "i: " << i << endl;
    // }
  }
}

// class nCk {
// private:
//     ll m_mod;
//     ll m_precompChooseMax = -1;
//     ll m_precompModInverseMax = -1;

// public:
//     // mod must be a prime number
//     nCk(ll mod) : m_mod(mod) {}

//     vector<vector<ll>> m_chooseResult;
//     vector<ll> m_modInverseResult;

//     // x^y % m_mod
//     ll modPow(ll x, ll y)
//     {
//         ll r = 1, a = x;
//         while (y > 0) {
//             if ((y&1) == 1) {
//                 r = (r * a) % m_mod;
//             }
//             a = (a * a) % m_mod;
//             y /= 2;
//         }
//         return r;
//     }

//     // a^-1 ≡ a^(p-2) (mod p)   (p is prime)
//     ll modInverse(ll x)
//     {
//         if (x <= m_precompModInverseMax) return m_modInverseResult[x];
//         else return modPow(x, m_mod-2);
//     }

//     // Modular division x / y, find modular multiplicative inverse of y
//     // and multiply by x.
//     ll modDivision(ll p, ll q)
//     {
//         return (p * modInverse(q)) % m_mod;
//     }

//     // Binomial coifficient C(n,k) in O(k) time.
//     ll choose(ll n, ll k)
//     {
//         if (max(n, k) <= m_precompChooseMax) {
//             return m_chooseResult[n][k];
//         }

//         if (k > n) {
//             return 0;
//         }
//         ll p = 1, q = 1;
//         for (int i=1; i<=k; i++) {
//             q = (q * i) % m_mod;
//             p = (p * (n - i + 1)) % m_mod;
//         }
//         return modDivision(p, q);
//     }

//     // precompute nCk
//     void precompChoose(ll n_max) {
//         assert(n_max > 0);
//         m_chooseResult.resize(n_max+1, vector<ll>(n_max+1));
//         m_chooseResult[0][0] = 1;
//         FOR(i, 1, n_max + 1) {
//             m_chooseResult[i][0] = 1;
//             FOR(j, 1, n_max + 1) {
//                 m_chooseResult[i][j]
//                     = (m_chooseResult[i - 1][j - 1] + m_chooseResult[i -
//                     1][j]) % m_mod;
//             }
//         }
//         m_precompChooseMax = n_max;
//     }
//     // precompute modInverse
//     void precompModInverse(ll n_max) {
//         assert(n_max > 0);
//         m_modInverseResult.resize(n_max + 1);
//         FOR(i, 1, n_max + 1) {
//             m_modInverseResult[i] = modInverse(i);
//         }
//         m_precompModInverseMax = n_max;
//     }
// };

ll solve(ll N, ll A, ll B, ll K) {
  vector<ll> nck_table(N + 1);
  makeCTable(N, N, nck_table);
  // REP(n, N+1) {
  //     cerr << N << " C " << n << " = " << nck_table[n] << endl;
  // }

  // REP(k, N+1) {
  //     if(k == 0) {
  //         nck_table[k] =
  //     }
  // }

  // nCk nck(MOD);
  // nck.precompChoose(N);

  // A * x + B * y == K

  ll ans = 0;
  REP(x, N + 1) {
    auto K2 = K - A * x;
    if (K2 % B == 0) {
      auto y = K2 / B;
      if (y > N)
        continue;
      if (y < 0)
        continue;
      // cerr << "x, y = " << x << "," << y << endl;
      ans += nck_table[x] * nck_table[y];
      ans %= MOD;
    }
  }
  return ans;

  // // ll gcd_num = gcd(A, B);
  // // cerr << "gcd(A,B):" << gcd_num << endl;

  // ll gcd_num = gcd(gcd(A, B), K);
  // cerr << "gcd(A,B,K):" << gcd_num << endl;

  // ll A2 = A / gcd_num;
  // ll B2 = B / gcd_num;
  // ll K2 = K / gcd_num;
}

int main(void) {
  cin.sync_with_stdio(false);
  ll N, A, B, K;
  cin >> N >> A >> B >> K;
  cout << solve(N, A, B, K) << endl;

  while (1) {
    ll N = rand() % 100000;
    ll A = rand() % 100000;
    ll B = rand() % 100000;
    ll K = abs((ll)rand() * rand() * rand()) % 18000000000;
    cout << N << " " << A << " " << B << " " << K << endl;
    solve(N, A, B, K);
  }

  return 0;
}


Fixed submission:
#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

using namespace std;
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;

#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define FOR(i, a, b) for (int i = (a); i < (int)(b); ++i)
#define ALL(c) (c).begin(), (c).end()
#define SIZE(v) ((int)v.size())

#define pb push_back
#define mp make_pair
#define mt make_tuple

ll MOD = 998244353;

// ll gcd(ll a, ll b)
// {
//     while(1)
//     {
//         if (a == 0) return b;
//         b %= a;
//         if (b == 0) return a;
//         a %= b;
//     }
// }

ll modPow(ll x, ll y) {
  ll r = 1, a = x;
  while (y > 0) {
    if ((y & 1) == 1) {
      r = (r * a) % MOD;
    }
    a = (a * a) % MOD;
    y /= 2;
  }

  return r;
}
// Modular multiplicative inverse through Fermat's little theorem:
// フェルマーの小定理より, a^-1 ≡ a^(p-2) (mod p) というのを使うらしい
// ただし、pが素数の時しか成り立たない
ll modInverse(ll x) { return modPow(x, MOD - 2); }

// Modular division x / y, find modular multiplicative inverse of y
// and multiply by x.
ll modDivision(ll p, ll q) { return (p * modInverse(q)) % MOD; }

// Binomial coifficient C(n,k) in O(k) time.
void makeCTable(ll n, ll k, vector<ll> &table) {
  if (k > n) {
    return;
  }
  ll p = 1, q = 1;
  table[0] = 1;
  for (ll i = 1; i <= k; i++) {
    q = (q * i) % MOD;
    p = (p * (n - i + 1)) % MOD;
    table[i] = modDivision(p, q);
    // if (i % 1000 == 0) {
    //     cerr << "i: " << i << endl;
    // }
  }
}

// class nCk {
// private:
//     ll m_mod;
//     ll m_precompChooseMax = -1;
//     ll m_precompModInverseMax = -1;

// public:
//     // mod must be a prime number
//     nCk(ll mod) : m_mod(mod) {}

//     vector<vector<ll>> m_chooseResult;
//     vector<ll> m_modInverseResult;

//     // x^y % m_mod
//     ll modPow(ll x, ll y)
//     {
//         ll r = 1, a = x;
//         while (y > 0) {
//             if ((y&1) == 1) {
//                 r = (r * a) % m_mod;
//             }
//             a = (a * a) % m_mod;
//             y /= 2;
//         }
//         return r;
//     }

//     // a^-1 ≡ a^(p-2) (mod p)   (p is prime)
//     ll modInverse(ll x)
//     {
//         if (x <= m_precompModInverseMax) return m_modInverseResult[x];
//         else return modPow(x, m_mod-2);
//     }

//     // Modular division x / y, find modular multiplicative inverse of y
//     // and multiply by x.
//     ll modDivision(ll p, ll q)
//     {
//         return (p * modInverse(q)) % m_mod;
//     }

//     // Binomial coifficient C(n,k) in O(k) time.
//     ll choose(ll n, ll k)
//     {
//         if (max(n, k) <= m_precompChooseMax) {
//             return m_chooseResult[n][k];
//         }

//         if (k > n) {
//             return 0;
//         }
//         ll p = 1, q = 1;
//         for (int i=1; i<=k; i++) {
//             q = (q * i) % m_mod;
//             p = (p * (n - i + 1)) % m_mod;
//         }
//         return modDivision(p, q);
//     }

//     // precompute nCk
//     void precompChoose(ll n_max) {
//         assert(n_max > 0);
//         m_chooseResult.resize(n_max+1, vector<ll>(n_max+1));
//         m_chooseResult[0][0] = 1;
//         FOR(i, 1, n_max + 1) {
//             m_chooseResult[i][0] = 1;
//             FOR(j, 1, n_max + 1) {
//                 m_chooseResult[i][j]
//                     = (m_chooseResult[i - 1][j - 1] + m_chooseResult[i -
//                     1][j]) % m_mod;
//             }
//         }
//         m_precompChooseMax = n_max;
//     }
//     // precompute modInverse
//     void precompModInverse(ll n_max) {
//         assert(n_max > 0);
//         m_modInverseResult.resize(n_max + 1);
//         FOR(i, 1, n_max + 1) {
//             m_modInverseResult[i] = modInverse(i);
//         }
//         m_precompModInverseMax = n_max;
//     }
// };

ll solve(ll N, ll A, ll B, ll K) {
  vector<ll> nck_table(N + 1);
  makeCTable(N, N, nck_table);
  // REP(n, N+1) {
  //     cerr << N << " C " << n << " = " << nck_table[n] << endl;
  // }

  // REP(k, N+1) {
  //     if(k == 0) {
  //         nck_table[k] =
  //     }
  // }

  // nCk nck(MOD);
  // nck.precompChoose(N);

  // A * x + B * y == K

  ll ans = 0;
  REP(x, N + 1) {
    auto K2 = K - A * x;
    if (K2 % B == 0) {
      auto y = K2 / B;
      if (y > N)
        continue;
      if (y < 0)
        continue;
      // cerr << "x, y = " << x << "," << y << endl;
      ans += nck_table[x] * nck_table[y];
      ans %= MOD;
    }
  }
  return ans;

  // // ll gcd_num = gcd(A, B);
  // // cerr << "gcd(A,B):" << gcd_num << endl;

  // ll gcd_num = gcd(gcd(A, B), K);
  // cerr << "gcd(A,B,K):" << gcd_num << endl;

  // ll A2 = A / gcd_num;
  // ll B2 = B / gcd_num;
  // ll K2 = K / gcd_num;
}

int main(void) {
  cin.sync_with_stdio(false);
  ll N, A, B, K;
  cin >> N >> A >> B >> K;
  cout << solve(N, A, B, K) << endl;

  // while(1) {
  //     ll N = rand() % 100000;
  //     ll A = rand() % 100000;
  //     ll B = rand() % 100000;
  //     ll K = abs((ll)rand() * rand() * rand()) % 18000000000;
  //     cout << N << " " << A << " " << B << " " << K << endl;
  //     solve(N, A, B, K);
  // }

  return 0;
}