Problem p02634 (C++) — buggy submission, verdict: Time Limit Exceeded

// include
//------------------------------------------
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <utility>
#include <vector>

#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

#include <stdexcept>

using namespace std;

// type alias
using ll = long long;
using ull = unsigned long long;
using comp = complex<double>;

const ll MOD = 1000000007LL;
const double PI = 3.14159265358979323846;

// conversion
//------------------------------------------
inline int toint(string s) {
  int v;
  istringstream sin(s);
  sin >> v;
  return v;
}
template <class t> inline string tostring(t x) {
  ostringstream sout;
  sout << x;
  return sout.str();
}

// for loop
#define REP(i, n) for ((i) = 0; (i) < (ll)(n); (i)++)

// debug
#define DUMP(x) cerr << #x << " = " << (x) << endl
#define DEBUG(x)                                                               \\
  cerr << #x << " = " << (x) << " (l" << __line__ << ")"                       \\
       << " " << __file__ << endl

template <class Integer> class ResidueInteger {
private:
  Integer mod_;
  Integer n_;
  static Integer global_mod_;

  // computational complexity: o(log(max(a, b)))
  static inline pair<Integer, Integer> getBezoutsIdentitySolution(Integer a,
                                                                  Integer b) {
    if (b == 0) {
      return {1, 0};
    }
    auto sol = getBezoutsIdentitySolution(b, a % b);
    return {sol.second, sol.first - (a / b) * sol.second};
  }

public:
  static Integer default_mod_;

  Integer getModValue(const Integer &n) const {
    return (n % mod_ + mod_) % mod_;
  }

  // computational complexity: o(log(max(n, mod)))
  inline Integer getModInverse(const Integer &n) const {
    auto sol = getBezoutsIdentitySolution(n, mod_);
    if (n * sol.first + mod_ * sol.second != 1) {
      return -1;
    }
    return getModValue(sol.first);
  }

  ResidueInteger() : mod_(default_mod_), n_(getModValue(0)) {}
  ResidueInteger(Integer n) : mod_(default_mod_), n_(getModValue(n)) {}
  ResidueInteger(Integer n, Integer mod) : mod_(mod), n_(getModValue(n)) {}

  inline ResidueInteger operator+(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ + rhs.n_, this->mod_};
  }
  inline ResidueInteger operator+(const Integer &rhs) const {
    return {this->n_ + getModValue(rhs), this->mod_};
  }
  friend inline ResidueInteger operator+(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) + rhs.n_, rhs.mod_};
  }
  inline ResidueInteger &operator+=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ + rhs.n_);
    return *this;
  }
  inline ResidueInteger &operator+=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ + getModValue(rhs));
    return *this;
  }

  inline ResidueInteger operator-(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ - rhs.n_, this->mod_};
  }
  inline ResidueInteger operator-(const Integer &rhs) const {
    return {this->n_ - getModValue(rhs), this->mod_};
  }
  friend inline ResidueInteger operator-(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) - rhs.n_, rhs.mod_};
  }
  inline ResidueInteger &operator-=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ - rhs.n_);
    return *this;
  }
  inline ResidueInteger &operator-=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ - getModValue(rhs));
    return *this;
  }

  inline ResidueInteger operator*(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ * rhs.n_, this->mod_};
  }
  inline ResidueInteger operator*(const Integer &rhs) const {
    return {this->n_ * getModValue(rhs), this->mod_};
  }
  friend inline ResidueInteger operator*(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) * rhs.n_, rhs.mod_};
  }
  inline ResidueInteger &operator*=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ * rhs.n_);
    return *this;
  }
  inline ResidueInteger &operator*=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ * getModValue(rhs));
    return *this;
  }

  inline ResidueInteger operator/(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ * getModInverse(rhs.n_), this->mod_};
  }
  inline ResidueInteger operator/(const Integer &rhs) const {
    return {this->n_ * getModInverse(getModValue(rhs)), this->mod_};
  }
  friend inline ResidueInteger operator/(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) * rhs.getModInverse(rhs.n_), rhs.mod_};
  }
  inline ResidueInteger &operator/=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ * getModInverse(rhs.n_));
    return *this;
  }
  inline ResidueInteger &operator/=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ * getModInverse(getModValue(rhs)));
    return *this;
  }

  inline bool operator==(const ResidueInteger &rhs) const {
    return (this->n_ == rhs.n_) && (this->mod_ == rhs.mod_);
  }
  inline bool operator==(const Integer &rhs) const {
    return this->n_ == getModValue(rhs);
  }
  friend bool operator==(const Integer &lhs, const ResidueInteger &rhs) {
    return rhs.getModValue(lhs) == rhs.n_;
  }

  Integer get_n() const { return n_; }

  friend std::ostream &operator<<(std::ostream &lhs,
                                  const ResidueInteger &rhs) {
    return lhs << rhs.n_;
  }

  friend std::istream &operator>>(std::istream &lhs, ResidueInteger &rhs) {
    lhs >> rhs.n_;
    return lhs;
  }
};
using rll = ResidueInteger<ll>;
template <> ll rll::default_mod_ = 998244353LL;

int solve() {
  ll A, B, C, D;
  cin >> A >> B >> C >> D;
  vector<vector<ll>> results =
      vector<vector<ll>>(C - A + 1, vector<ll>(D - B + 1));

  ll rd, lu, ld, res;
  results[0][0] = 1;
  for (ll k = 1; k <= C - A + D - B; ++k) {
    for (ll e = max(k - (D - B), 0LL); e <= C - A && 0 <= k - e; ++e) {
      ll f = k - e;

      rd = (e - 1 >= 0 ? results[e - 1][f] : 0);
      lu = (f - 1 >= 0 ? results[e][f - 1] : 0);
      ld = (e - 1 >= 0 && f - 1 >= 0 ? results[e - 1][f - 1] : 0);
      res = rd * (f + B) % rll::default_mod_ +
            lu * (e + A) % rll::default_mod_ -
            ld * (e + A - 1) % rll::default_mod_ * (f + B - 1) %
                rll::default_mod_;
      res = (res + rll::default_mod_) % rll::default_mod_;

      results[e][f] = res;
    }
  }

  cout << results[C - A][D - B] << endl;

  return 0;
}

// main function
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  solve();

  return 0;
}


Error: TLE

Fixed submission:

// include
//------------------------------------------
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <utility>
#include <vector>

#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

#include <stdexcept>

using namespace std;

// type alias
using ll = long long;
using ull = unsigned long long;
using comp = complex<double>;

const ll MOD = 1000000007LL;
const double PI = 3.14159265358979323846;

// conversion
//------------------------------------------
inline int toint(string s) {
  int v;
  istringstream sin(s);
  sin >> v;
  return v;
}
template <class t> inline string tostring(t x) {
  ostringstream sout;
  sout << x;
  return sout.str();
}

// for loop
#define REP(i, n) for ((i) = 0; (i) < (ll)(n); (i)++)

// debug
#define DUMP(x) cerr << #x << " = " << (x) << endl
#define DEBUG(x)                                                               \\
  cerr << #x << " = " << (x) << " (l" << __line__ << ")"                       \\
       << " " << __file__ << endl

template <class Integer> class ResidueInteger {
private:
  Integer mod_;
  Integer n_;
  static Integer global_mod_;

  // computational complexity: o(log(max(a, b)))
  static inline pair<Integer, Integer> getBezoutsIdentitySolution(Integer a,
                                                                  Integer b) {
    if (b == 0) {
      return {1, 0};
    }
    auto sol = getBezoutsIdentitySolution(b, a % b);
    return {sol.second, sol.first - (a / b) * sol.second};
  }

public:
  static Integer default_mod_;

  Integer getModValue(const Integer &n) const {
    return (n % mod_ + mod_) % mod_;
  }

  // computational complexity: o(log(max(n, mod)))
  inline Integer getModInverse(const Integer &n) const {
    auto sol = getBezoutsIdentitySolution(n, mod_);
    if (n * sol.first + mod_ * sol.second != 1) {
      return -1;
    }
    return getModValue(sol.first);
  }

  ResidueInteger() : mod_(default_mod_), n_(getModValue(0)) {}
  ResidueInteger(Integer n) : mod_(default_mod_), n_(getModValue(n)) {}
  ResidueInteger(Integer n, Integer mod) : mod_(mod), n_(getModValue(n)) {}

  inline ResidueInteger operator+(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ + rhs.n_, this->mod_};
  }
  inline ResidueInteger operator+(const Integer &rhs) const {
    return {this->n_ + getModValue(rhs), this->mod_};
  }
  friend inline ResidueInteger operator+(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) + rhs.n_, rhs.mod_};
  }
  inline ResidueInteger &operator+=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ + rhs.n_);
    return *this;
  }
  inline ResidueInteger &operator+=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ + getModValue(rhs));
    return *this;
  }

  inline ResidueInteger operator-(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ - rhs.n_, this->mod_};
  }
  inline ResidueInteger operator-(const Integer &rhs) const {
    return {this->n_ - getModValue(rhs), this->mod_};
  }
  friend inline ResidueInteger operator-(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) - rhs.n_, rhs.mod_};
  }
  inline ResidueInteger &operator-=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ - rhs.n_);
    return *this;
  }
  inline ResidueInteger &operator-=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ - getModValue(rhs));
    return *this;
  }

  inline ResidueInteger operator*(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ * rhs.n_, this->mod_};
  }
  inline ResidueInteger operator*(const Integer &rhs) const {
    return {this->n_ * getModValue(rhs), this->mod_};
  }
  friend inline ResidueInteger operator*(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) * rhs.n_, rhs.mod_};
  }
  inline ResidueInteger &operator*=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ * rhs.n_);
    return *this;
  }
  inline ResidueInteger &operator*=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ * getModValue(rhs));
    return *this;
  }

  inline ResidueInteger operator/(const ResidueInteger &rhs) const {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    return {this->n_ * getModInverse(rhs.n_), this->mod_};
  }
  inline ResidueInteger operator/(const Integer &rhs) const {
    return {this->n_ * getModInverse(getModValue(rhs)), this->mod_};
  }
  friend inline ResidueInteger operator/(const Integer &lhs,
                                         const ResidueInteger &rhs) {
    return {rhs.getModValue(lhs) * rhs.getModInverse(rhs.n_), rhs.mod_};
  }
  inline ResidueInteger &operator/=(const ResidueInteger &rhs) {
    if (this->mod_ != rhs.mod_) {
      throw invalid_argument("The mods of both operands should be equal.");
    }
    this->n_ = getModValue(this->n_ * getModInverse(rhs.n_));
    return *this;
  }
  inline ResidueInteger &operator/=(const Integer &rhs) {
    this->n_ = getModValue(this->n_ * getModInverse(getModValue(rhs)));
    return *this;
  }

  inline bool operator==(const ResidueInteger &rhs) const {
    return (this->n_ == rhs.n_) && (this->mod_ == rhs.mod_);
  }
  inline bool operator==(const Integer &rhs) const {
    return this->n_ == getModValue(rhs);
  }
  friend bool operator==(const Integer &lhs, const ResidueInteger &rhs) {
    return rhs.getModValue(lhs) == rhs.n_;
  }

  Integer get_n() const { return n_; }

  friend std::ostream &operator<<(std::ostream &lhs,
                                  const ResidueInteger &rhs) {
    return lhs << rhs.n_;
  }

  friend std::istream &operator>>(std::istream &lhs, ResidueInteger &rhs) {
    lhs >> rhs.n_;
    return lhs;
  }
};
using rll = ResidueInteger<ll>;
template <> ll rll::default_mod_ = 998244353LL;

ll calc(ll c, ll d, ll a, ll b, vector<vector<ll>> &results) {
  if (c < a || d < b)
    return 0;
  if (results[c][d] != -1)
    return results[c][d];

  rll rd = calc(c - 1, d, a, b, results);
  rll lu = calc(c, d - 1, a, b, results);
  rll ld = calc(c - 1, d - 1, a, b, results);

  rll res = rd * d + lu * c - ld * (c - 1) * (d - 1);

  results[c][d] = res.get_n();

  return results[c][d];
}

int solve() {
  ll A, B, C, D;
  cin >> A >> B >> C >> D;
  vector<vector<ll>> results =
      vector<vector<ll>>(C - A + 1, vector<ll>(D - B + 1));

  rll rd, lu, ld, res;
  results[0][0] = 1;
  for (ll k = 1; k <= C - A + D - B; ++k) {
    for (ll e = max(k - (D - B), 0LL); e <= C - A && 0 <= k - e; ++e) {
      ll f = k - e;

      rd = (e - 1 >= 0 ? results[e - 1][f] : 0);
      lu = (f - 1 >= 0 ? results[e][f - 1] : 0);
      ld = (e - 1 >= 0 && f - 1 >= 0 ? results[e - 1][f - 1] : 0);
      res = rd * (f + B) + lu * (e + A) - ld * (e + A - 1) * (f + B - 1);

      results[e][f] = res.get_n();
    }
  }

  cout << results[C - A][D - B] << endl;

  return 0;
}

// main function
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  solve();

  return 0;
}