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

#include <bits/stdc++.h>
using namespace std;
#if __has_include(<boost/multiprecision/cpp_int.hpp>)
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using bll = boost::multiprecision::cpp_int;
using bdouble = boost::multiprecision::cpp_dec_float_100;
using namespace boost::multiprecision;
#endif
#if __has_include(<boost/stacktrace.hpp>)
#define BOOST_STACKTRACE_USE_ADDR2LINE
#define BOOST_STACKTRACE_ADDR2LINE_LOCATION                                    \\
  / usr / local / opt / binutils / bin / addr2line
#define _GNU_SOURCE 1
#include <boost/stacktrace.hpp>
#endif
#ifdef LOCAL_TEST
namespace std {
template <typename T> class dvector : public std::vector<T> {
public:
  dvector() : std::vector<T>() {}
  explicit dvector(size_t n, const T &value = T()) : std::vector<T>(n, value) {}
  dvector(const std::vector<T> &v) : std::vector<T>(v) {}
  dvector(const std::initializer_list<T> il) : std::vector<T>(il) {}
  dvector(const std::string::iterator first, const std::string::iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::iterator first,
          const typename std::vector<T>::iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::reverse_iterator first,
          const typename std::vector<T>::reverse_iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::const_iterator first,
          const typename std::vector<T>::const_iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::const_reverse_iterator first,
          const typename std::vector<T>::const_reverse_iterator last)
      : std::vector<T>(first, last) {}
  T &operator[](size_t n) {
    try {
      return this->at(n);
    } catch (const std::exception &e) {
      std::cerr << boost::stacktrace::stacktrace() << '\\n';
      return this->at(n);
    }
  }
  const T &operator[](size_t n) const {
    try {
      return this->at(n);
    } catch (const std::exception &e) {
      std::cerr << boost::stacktrace::stacktrace() << '\\n';
      return this->at(n);
    }
  }
};
} // namespace std
class dbool {
private:
  bool boolvalue;

public:
  dbool() : boolvalue(false) {}
  dbool(bool b) : boolvalue(b) {}
  operator bool &() { return boolvalue; }
  operator const bool &() const { return boolvalue; }
};
#define vector dvector
#define bool dbool
#endif
#ifdef LOCAL_DEV
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::vector<T> &v) {
  for (size_t i = 0; i < v.size(); ++i) {
    s << v[i];
    if (i < v.size() - 1)
      s << "\\t";
  }
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s,
                         const std::vector<std::vector<T>> &vv) {
  s << "\\\\\\n";
  for (size_t i = 0; i < vv.size(); ++i) {
    s << vv[i] << "\\n";
  }
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::deque<T> &v) {
  for (size_t i = 0; i < v.size(); ++i) {
    s << v[i];
    if (i < v.size() - 1)
      s << "\\t";
  }
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::set<T> &se) {
  s << "{ ";
  for (auto itr = se.begin(); itr != se.end(); ++itr) {
    s << (*itr) << "\\t";
  }
  s << "}";
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::multiset<T> &se) {
  s << "{ ";
  for (auto itr = se.begin(); itr != se.end(); ++itr) {
    s << (*itr) << "\\t";
  }
  s << "}";
  return s;
}
template <typename T, size_t N>
std::ostream &operator<<(std::ostream &s, const std::array<T, N> &a) {
  s << "{ ";
  for (size_t i = 0; i < N; ++i) {
    s << a[i] << "\\t";
  }
  s << "}";
  return s;
}
template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &s, const std::map<T1, T2> &m) {
  s << "{\\n";
  for (auto itr = m.begin(); itr != m.end(); ++itr) {
    s << "\\t" << (*itr).first << " : " << (*itr).second << "\\n";
  }
  s << "}";
  return s;
}
template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &s, const std::pair<T1, T2> &p) {
  return s << "(" << p.first << ", " << p.second << ")";
}
class SIGFPE_exception : std::exception {};
class SIGSEGV_exception : std::exception {};
void catch_SIGFPE([[maybe_unused]] int e) {
  std::cerr << boost::stacktrace::stacktrace() << '\\n';
  throw SIGFPE_exception();
}
void catch_SIGSEGV([[maybe_unused]] int e) {
  std::cerr << boost::stacktrace::stacktrace() << '\\n';
  throw SIGSEGV_exception();
}
signed convertedmain();
signed main() {
  signal(SIGFPE, catch_SIGFPE);
  signal(SIGSEGV, catch_SIGSEGV);
  return convertedmain();
}
#define main() convertedmain()
void debug_impl() { std::cerr << '\\n'; }
template <typename Head, typename... Tail>
void debug_impl(Head head, Tail... tail) {
  std::cerr << " " << head << (sizeof...(tail) ? "," : "");
  debug_impl(tail...);
}
#define debug(...)                                                             \\
  do {                                                                         \\
    std::cerr << "(" << #__VA_ARGS__ << ") =";                                 \\
    debug_impl(__VA_ARGS__);                                                   \\
  } while (false)
#else
#define debug(...)                                                             \\
  do {                                                                         \\
  } while (false)
#endif
// #define int long long
using ll = long long;
// constexpr int INF = (ll)1e9 + 7;//INT_MAX=(1<<31)-1=2147483647
constexpr ll INF = (ll)1e18;  //(1LL<<63)-1=9223372036854775807
constexpr ll MOD = 998244353; //(ll)1e9 + 7;
constexpr double EPS = 1e-9;
constexpr ll dx[4] = {1, 0, -1, 0};
constexpr ll dy[4] = {0, 1, 0, -1};
constexpr ll dx8[8] = {1, 0, -1, 0, 1, 1, -1, -1};
constexpr ll dy8[8] = {0, 1, 0, -1, 1, -1, 1, -1};
#define rep(i, n) for (ll i = 0, i##_length = (n); i < i##_length; ++i)
#define repeq(i, n) for (ll i = 1, i##_length = (n); i <= i##_length; ++i)
#define rrep(i, n) for (ll i = (n)-1; i >= 0; --i)
#define rrepeq(i, n) for (ll i = (n); i >= 1; --i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
void p() { std::cout << '\\n'; }
template <typename Head, typename... Tail> void p(Head head, Tail... tail) {
  std::cout << head << (sizeof...(tail) ? " " : "");
  p(tail...);
}
template <typename T> inline void pv(std::vector<T> &v) {
  for (ll i = 0, N = v.size(); i < N; i++)
    std::cout << v[i] << " \\n"[i == N - 1];
}
template <typename T> inline bool chmax(T &a, T b) {
  return a < b && (a = b, true);
}
template <typename T> inline bool chmin(T &a, T b) {
  return a > b && (a = b, true);
}
template <typename T> inline void uniq(std::vector<T> &v) {
  v.erase(std::unique(v.begin(), v.end()), v.end());
}

/*-----8<-----template-----8<-----*/
inline constexpr ll extgcd(ll a, ll b, ll &x, ll &y) {
  ll g = a;
  x = 1;
  y = 0;
  if (b) {
    g = extgcd(b, a % b, y, x);
    y -= a / b * x;
  }
  return g;
}
inline constexpr ll invmod(ll a, ll m = MOD) {
  ll x = 0, y = 0;
  extgcd(a, m, x, y);
  return (x + m) % m;
}
class Modint {
public:
  ll _num;
  constexpr Modint() : _num() { _num = 0; }
  constexpr Modint(ll x) : _num() {
    _num = x % MOD;
    if (_num < 0)
      _num += MOD;
  }
  inline constexpr Modint operator=(int x) {
    _num = x % MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator=(ll x) {
    _num = x % MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  // inline constexpr Modint operator= (Modint x){ _num = x._num; return *this;
  // }
  inline constexpr Modint operator+(int x) { return Modint(_num + x); }
  inline constexpr Modint operator+(ll x) { return Modint(_num + x); }
  inline constexpr Modint operator+(Modint x) {
    ll a = _num + x._num;
    if (a >= MOD)
      a -= MOD;
    return Modint{a};
  }
  inline constexpr Modint operator+=(int x) {
    _num += x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator+=(ll x) {
    _num += x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator+=(Modint x) {
    _num += x._num;
    if (_num >= MOD)
      _num -= MOD;
    return *this;
  }
  inline constexpr Modint operator++() {
    _num++;
    if (_num == MOD)
      _num = 0;
    return *this;
  }
  inline constexpr Modint operator-(int x) { return Modint(_num - x); }
  inline constexpr Modint operator-(ll x) { return Modint(_num - x); }
  inline constexpr Modint operator-(Modint x) {
    ll a = _num - x._num;
    if (a < 0)
      a += MOD;
    return Modint{a};
  }
  inline constexpr Modint operator-=(int x) {
    _num -= x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator-=(ll x) {
    _num -= x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator-=(Modint x) {
    _num -= x._num;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator--() {
    _num--;
    if (_num == -1)
      _num = MOD - 1;
    return *this;
  }
  inline constexpr Modint operator*(int x) { return Modint(_num * (x % MOD)); }
  inline constexpr Modint operator*(ll x) { return Modint(_num * (x % MOD)); }
  inline constexpr Modint operator*(Modint x) {
    return Modint{_num * x._num % MOD};
  }
  inline constexpr Modint operator*=(int x) {
    _num *= Modint(x);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator*=(ll x) {
    _num *= Modint(x);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator*=(Modint x) {
    _num *= x._num;
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator/(int x) {
    return Modint(_num * invmod(Modint(x), MOD));
  }
  inline constexpr Modint operator/(ll x) {
    return Modint(_num * invmod(Modint(x), MOD));
  }
  inline constexpr Modint operator/(Modint x) {
    return Modint{_num * invmod(x._num, MOD) % MOD};
  }
  inline constexpr Modint operator/=(int x) {
    _num *= invmod(Modint(x), MOD);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator/=(ll x) {
    _num *= invmod(Modint(x), MOD);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator/=(Modint x) {
    _num *= invmod(x._num, MOD);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint pow(ll n) {
    ll i = 1, x = n >= 0 ? n : -n;
    Modint ans = 1, cnt = n >= 0 ? *this : Modint(1) / *this;
    while (i <= x) {
      if (x & i) {
        ans *= cnt;
        x ^= i;
      }
      cnt *= cnt;
      i *= 2;
    }
    return ans;
  }
  inline constexpr operator ll() const { return _num; }
};
inline std::istream &operator>>(std::istream &s, Modint &x) {
  ll t;
  s >> t;
  x = t;
  return s;
}
vector<Modint> fac(1, 1), inv(1, 1);
inline void reserve(size_t a) {
  if (fac.size() >= a)
    return;
  if (a < fac.size() * 2)
    a = fac.size() * 2;
  if (a >= MOD)
    a = MOD;
  while (fac.size() < a)
    fac.push_back(fac.back() * ll(fac.size()));
  inv.resize(fac.size());
  inv.back() = Modint(1) / fac.back();
  for (ll i = inv.size() - 1; !inv[i - 1]; i--)
    inv[i - 1] = inv[i] * i;
}
inline Modint factorial(ll n) {
  if (n < 0)
    return 0;
  reserve(n + 1);
  return fac[n];
}
inline Modint nPk_loop(ll n, ll k) {
  if (n < k)
    return 0;
  Modint val(1);
  for (ll i = n; i > (n - k); i--)
    val *= i;
  return val;
}
inline Modint nCk_loop(ll n, ll k) {
  if (n < k)
    return 0;
  Modint val(1);
  k = min(k, n - k);
  for (ll i = n; i > (n - k); i--)
    val *= i;
  for (ll i = k; i > 1; i--)
    val /= i;
  return val;
};
inline Modint nPk(ll n, ll k) {
  if (k < 0 || n < k)
    return 0;
  if (n >= (ll)1e7)
    return nPk_loop(n, k);
  reserve(n + 1);
  return fac[n] * inv[n - k];
}
inline Modint nCk(ll n, ll k) {
  if (k < 0 || n < k)
    return 0;
  if (n >= (ll)1e7)
    return nCk_loop(n, k);
  reserve(n + 1);
  return fac[n] * inv[k] * inv[n - k];
}
inline Modint nHk(ll n, ll k) {
  return nCk(n + k - 1, k);
} // n種類のものから重複を許してk個選ぶ=玉k個と仕切りn-1個

/*
nCk：n!が間に合わないくらい巨大でkが小さいとき、素直に計算すると間に合う
のは1e7以上に組み込んであります auto f = [](ll n, ll k){ if(n<k)return
Modint(0); Modint val(1); k=min(k,n-k); for(ll i=n;i>(n-k);i--)val*=i; for(ll
i=k;i>1;i--)val/=i; return val;
        };
*/

namespace makevectordetail {
template <typename Tp, size_t N>
std::vector<Tp>
make_vector(std::vector<size_t> &sizes,
            typename std::enable_if<(N == 1), Tp const &>::type x) {
  return std::vector<Tp>(sizes[0], x);
}
template <typename Tp, size_t N>
auto make_vector(std::vector<size_t> &sizes,
                 typename std::enable_if<(N > 1), Tp const &>::type x) {
  size_t size = sizes[N - 1];
  sizes.pop_back();
  return std::vector<decltype(make_vector<Tp, N - 1>(sizes, x))>(
      size, make_vector<Tp, N - 1>(sizes, x));
}
} // namespace makevectordetail
template <typename Tp, typename sizetype, size_t N>
auto make_vector(sizetype const (&sizes)[N], Tp const &x = Tp()) {
  std::vector<size_t> s(N);
  for (size_t i = 0; i < N; ++i)
    s[i] = sizes[N - i - 1];
  return makevectordetail::make_vector<Tp, N>(s, x);
}
// vector<vector<vector<ll>>> dp = make_vector<ll>({1, 2, 3}, 0LL);
/*-----8<-----library-----8<-----*/

void solve() {
  ll A, B, C, D;
  cin >> A >> B >> C >> D;

  using dptype = Modint;
  ll vectorsize[] = {C + 1, D + 1, 3LL};
  vector<vector<vector<Modint>>> dp = make_vector<Modint>(vectorsize, 0);
  vector<bool> checked = vector<bool>((C + 1) * (D + 1) * 3, false);
  auto idx = [&](ll a, ll b, ll c) {
    return a + vectorsize[0] * b + vectorsize[0] * vectorsize[1] * c;
  };
  // c 最上段の黒マス　0:黒マスが0　1:黒マスが1 2:黒マスが複数
  auto f = [&](auto &&f, ll x, ll y, ll c) -> dptype {
    if (x == A && y == B)
      return (c == 0) ? 1 : 0;
    if (x < A || y < B)
      return 0;
    if (checked[idx(x, y, c)])
      return dp[x][y][c];

    dptype ans = 0;
    if (x == A) {
      if (c == 0) {
        dptype t = f(f, x, y - 1, 0) * (x - 1);
        ans = t;
      } else if (c == 1) {
        dptype t = f(f, x, y - 1, 0);
        dptype s = f(f, x, y - 1, 1) * (x - 1);
        ans = t + s;
      } else if (c == 2) {
        dptype t = f(f, x, y - 1, 1);
        dptype s = f(f, x, y - 1, 2) * x;
        ans = t + s;
      }
    } else if (y == B) {
      if (c == 0) {
        ;
      } else if (c == 1) {
        dptype t = f(f, x - 1, y, 1) * y;
        ans = t;
        if (x == A + 1)
          ans += y;
      } else if (c == 2) {
        ;
      }
    } else if (c == 0) {
      dptype t = f(f, x, y - 1, 0) * (x - 1);
      ans = t;
    } else if (c == 1) {
      dptype t = f(f, x, y - 1, 0);
      // dptype s=f(f,x,y-1,1)*(x-1);
      dptype u = 0;
      rep(i, 3) u += f(f, x - 1, y, i) * (y);
      ans = t + u;
    } else if (c == 2) {
      dptype t = f(f, x, y - 1, 1);
      dptype s = f(f, x, y - 1, 2) * x;
      ans = t + s;
    }

    checked[idx(x, y, c)] = true;
    return dp[x][y][c] = ans;
  };
  dptype ans = 0;
  rep(i, 3) ans += f(f, C, D, i);
  debug(dp);
  p(ans);
}

// https://atcoder.jp/contests/agc046/tasks/agc046_b
signed main() {
  solve();
  return 0;
}


Error: MLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
#if __has_include(<boost/multiprecision/cpp_int.hpp>)
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using bll = boost::multiprecision::cpp_int;
using bdouble = boost::multiprecision::cpp_dec_float_100;
using namespace boost::multiprecision;
#endif
#if __has_include(<boost/stacktrace.hpp>)
#define BOOST_STACKTRACE_USE_ADDR2LINE
#define BOOST_STACKTRACE_ADDR2LINE_LOCATION                                    \\
  / usr / local / opt / binutils / bin / addr2line
#define _GNU_SOURCE 1
#include <boost/stacktrace.hpp>
#endif
#ifdef LOCAL_TEST
namespace std {
template <typename T> class dvector : public std::vector<T> {
public:
  dvector() : std::vector<T>() {}
  explicit dvector(size_t n, const T &value = T()) : std::vector<T>(n, value) {}
  dvector(const std::vector<T> &v) : std::vector<T>(v) {}
  dvector(const std::initializer_list<T> il) : std::vector<T>(il) {}
  dvector(const std::string::iterator first, const std::string::iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::iterator first,
          const typename std::vector<T>::iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::reverse_iterator first,
          const typename std::vector<T>::reverse_iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::const_iterator first,
          const typename std::vector<T>::const_iterator last)
      : std::vector<T>(first, last) {}
  dvector(const typename std::vector<T>::const_reverse_iterator first,
          const typename std::vector<T>::const_reverse_iterator last)
      : std::vector<T>(first, last) {}
  T &operator[](size_t n) {
    try {
      return this->at(n);
    } catch (const std::exception &e) {
      std::cerr << boost::stacktrace::stacktrace() << '\\n';
      return this->at(n);
    }
  }
  const T &operator[](size_t n) const {
    try {
      return this->at(n);
    } catch (const std::exception &e) {
      std::cerr << boost::stacktrace::stacktrace() << '\\n';
      return this->at(n);
    }
  }
};
} // namespace std
class dbool {
private:
  bool boolvalue;

public:
  dbool() : boolvalue(false) {}
  dbool(bool b) : boolvalue(b) {}
  operator bool &() { return boolvalue; }
  operator const bool &() const { return boolvalue; }
};
#define vector dvector
#define bool dbool
#endif
#ifdef LOCAL_DEV
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::vector<T> &v) {
  for (size_t i = 0; i < v.size(); ++i) {
    s << v[i];
    if (i < v.size() - 1)
      s << "\\t";
  }
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s,
                         const std::vector<std::vector<T>> &vv) {
  s << "\\\\\\n";
  for (size_t i = 0; i < vv.size(); ++i) {
    s << vv[i] << "\\n";
  }
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::deque<T> &v) {
  for (size_t i = 0; i < v.size(); ++i) {
    s << v[i];
    if (i < v.size() - 1)
      s << "\\t";
  }
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::set<T> &se) {
  s << "{ ";
  for (auto itr = se.begin(); itr != se.end(); ++itr) {
    s << (*itr) << "\\t";
  }
  s << "}";
  return s;
}
template <typename T>
std::ostream &operator<<(std::ostream &s, const std::multiset<T> &se) {
  s << "{ ";
  for (auto itr = se.begin(); itr != se.end(); ++itr) {
    s << (*itr) << "\\t";
  }
  s << "}";
  return s;
}
template <typename T, size_t N>
std::ostream &operator<<(std::ostream &s, const std::array<T, N> &a) {
  s << "{ ";
  for (size_t i = 0; i < N; ++i) {
    s << a[i] << "\\t";
  }
  s << "}";
  return s;
}
template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &s, const std::map<T1, T2> &m) {
  s << "{\\n";
  for (auto itr = m.begin(); itr != m.end(); ++itr) {
    s << "\\t" << (*itr).first << " : " << (*itr).second << "\\n";
  }
  s << "}";
  return s;
}
template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &s, const std::pair<T1, T2> &p) {
  return s << "(" << p.first << ", " << p.second << ")";
}
class SIGFPE_exception : std::exception {};
class SIGSEGV_exception : std::exception {};
void catch_SIGFPE([[maybe_unused]] int e) {
  std::cerr << boost::stacktrace::stacktrace() << '\\n';
  throw SIGFPE_exception();
}
void catch_SIGSEGV([[maybe_unused]] int e) {
  std::cerr << boost::stacktrace::stacktrace() << '\\n';
  throw SIGSEGV_exception();
}
signed convertedmain();
signed main() {
  signal(SIGFPE, catch_SIGFPE);
  signal(SIGSEGV, catch_SIGSEGV);
  return convertedmain();
}
#define main() convertedmain()
void debug_impl() { std::cerr << '\\n'; }
template <typename Head, typename... Tail>
void debug_impl(Head head, Tail... tail) {
  std::cerr << " " << head << (sizeof...(tail) ? "," : "");
  debug_impl(tail...);
}
#define debug(...)                                                             \\
  do {                                                                         \\
    std::cerr << "(" << #__VA_ARGS__ << ") =";                                 \\
    debug_impl(__VA_ARGS__);                                                   \\
  } while (false)
#else
#define debug(...)                                                             \\
  do {                                                                         \\
  } while (false)
#endif
// #define int long long
using ll = long long;
// constexpr int INF = (ll)1e9 + 7;//INT_MAX=(1<<31)-1=2147483647
constexpr ll INF = (ll)1e18;  //(1LL<<63)-1=9223372036854775807
constexpr ll MOD = 998244353; //(ll)1e9 + 7;
constexpr double EPS = 1e-9;
constexpr ll dx[4] = {1, 0, -1, 0};
constexpr ll dy[4] = {0, 1, 0, -1};
constexpr ll dx8[8] = {1, 0, -1, 0, 1, 1, -1, -1};
constexpr ll dy8[8] = {0, 1, 0, -1, 1, -1, 1, -1};
#define rep(i, n) for (ll i = 0, i##_length = (n); i < i##_length; ++i)
#define repeq(i, n) for (ll i = 1, i##_length = (n); i <= i##_length; ++i)
#define rrep(i, n) for (ll i = (n)-1; i >= 0; --i)
#define rrepeq(i, n) for (ll i = (n); i >= 1; --i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
void p() { std::cout << '\\n'; }
template <typename Head, typename... Tail> void p(Head head, Tail... tail) {
  std::cout << head << (sizeof...(tail) ? " " : "");
  p(tail...);
}
template <typename T> inline void pv(std::vector<T> &v) {
  for (ll i = 0, N = v.size(); i < N; i++)
    std::cout << v[i] << " \\n"[i == N - 1];
}
template <typename T> inline bool chmax(T &a, T b) {
  return a < b && (a = b, true);
}
template <typename T> inline bool chmin(T &a, T b) {
  return a > b && (a = b, true);
}
template <typename T> inline void uniq(std::vector<T> &v) {
  v.erase(std::unique(v.begin(), v.end()), v.end());
}

/*-----8<-----template-----8<-----*/
inline constexpr ll extgcd(ll a, ll b, ll &x, ll &y) {
  ll g = a;
  x = 1;
  y = 0;
  if (b) {
    g = extgcd(b, a % b, y, x);
    y -= a / b * x;
  }
  return g;
}
inline constexpr ll invmod(ll a, ll m = MOD) {
  ll x = 0, y = 0;
  extgcd(a, m, x, y);
  return (x + m) % m;
}
class Modint {
public:
  ll _num;
  constexpr Modint() : _num() { _num = 0; }
  constexpr Modint(ll x) : _num() {
    _num = x % MOD;
    if (_num < 0)
      _num += MOD;
  }
  inline constexpr Modint operator=(int x) {
    _num = x % MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator=(ll x) {
    _num = x % MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  // inline constexpr Modint operator= (Modint x){ _num = x._num; return *this;
  // }
  inline constexpr Modint operator+(int x) { return Modint(_num + x); }
  inline constexpr Modint operator+(ll x) { return Modint(_num + x); }
  inline constexpr Modint operator+(Modint x) {
    ll a = _num + x._num;
    if (a >= MOD)
      a -= MOD;
    return Modint{a};
  }
  inline constexpr Modint operator+=(int x) {
    _num += x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator+=(ll x) {
    _num += x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator+=(Modint x) {
    _num += x._num;
    if (_num >= MOD)
      _num -= MOD;
    return *this;
  }
  inline constexpr Modint operator++() {
    _num++;
    if (_num == MOD)
      _num = 0;
    return *this;
  }
  inline constexpr Modint operator-(int x) { return Modint(_num - x); }
  inline constexpr Modint operator-(ll x) { return Modint(_num - x); }
  inline constexpr Modint operator-(Modint x) {
    ll a = _num - x._num;
    if (a < 0)
      a += MOD;
    return Modint{a};
  }
  inline constexpr Modint operator-=(int x) {
    _num -= x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator-=(ll x) {
    _num -= x;
    _num %= MOD;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator-=(Modint x) {
    _num -= x._num;
    if (_num < 0)
      _num += MOD;
    return *this;
  }
  inline constexpr Modint operator--() {
    _num--;
    if (_num == -1)
      _num = MOD - 1;
    return *this;
  }
  inline constexpr Modint operator*(int x) { return Modint(_num * (x % MOD)); }
  inline constexpr Modint operator*(ll x) { return Modint(_num * (x % MOD)); }
  inline constexpr Modint operator*(Modint x) {
    return Modint{_num * x._num % MOD};
  }
  inline constexpr Modint operator*=(int x) {
    _num *= Modint(x);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator*=(ll x) {
    _num *= Modint(x);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator*=(Modint x) {
    _num *= x._num;
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator/(int x) {
    return Modint(_num * invmod(Modint(x), MOD));
  }
  inline constexpr Modint operator/(ll x) {
    return Modint(_num * invmod(Modint(x), MOD));
  }
  inline constexpr Modint operator/(Modint x) {
    return Modint{_num * invmod(x._num, MOD) % MOD};
  }
  inline constexpr Modint operator/=(int x) {
    _num *= invmod(Modint(x), MOD);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator/=(ll x) {
    _num *= invmod(Modint(x), MOD);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint operator/=(Modint x) {
    _num *= invmod(x._num, MOD);
    _num %= MOD;
    return *this;
  }
  inline constexpr Modint pow(ll n) {
    ll i = 1, x = n >= 0 ? n : -n;
    Modint ans = 1, cnt = n >= 0 ? *this : Modint(1) / *this;
    while (i <= x) {
      if (x & i) {
        ans *= cnt;
        x ^= i;
      }
      cnt *= cnt;
      i *= 2;
    }
    return ans;
  }
  inline constexpr operator ll() const { return _num; }
};
inline std::istream &operator>>(std::istream &s, Modint &x) {
  ll t;
  s >> t;
  x = t;
  return s;
}
vector<Modint> fac(1, 1), inv(1, 1);
inline void reserve(size_t a) {
  if (fac.size() >= a)
    return;
  if (a < fac.size() * 2)
    a = fac.size() * 2;
  if (a >= MOD)
    a = MOD;
  while (fac.size() < a)
    fac.push_back(fac.back() * ll(fac.size()));
  inv.resize(fac.size());
  inv.back() = Modint(1) / fac.back();
  for (ll i = inv.size() - 1; !inv[i - 1]; i--)
    inv[i - 1] = inv[i] * i;
}
inline Modint factorial(ll n) {
  if (n < 0)
    return 0;
  reserve(n + 1);
  return fac[n];
}
inline Modint nPk_loop(ll n, ll k) {
  if (n < k)
    return 0;
  Modint val(1);
  for (ll i = n; i > (n - k); i--)
    val *= i;
  return val;
}
inline Modint nCk_loop(ll n, ll k) {
  if (n < k)
    return 0;
  Modint val(1);
  k = min(k, n - k);
  for (ll i = n; i > (n - k); i--)
    val *= i;
  for (ll i = k; i > 1; i--)
    val /= i;
  return val;
};
inline Modint nPk(ll n, ll k) {
  if (k < 0 || n < k)
    return 0;
  if (n >= (ll)1e7)
    return nPk_loop(n, k);
  reserve(n + 1);
  return fac[n] * inv[n - k];
}
inline Modint nCk(ll n, ll k) {
  if (k < 0 || n < k)
    return 0;
  if (n >= (ll)1e7)
    return nCk_loop(n, k);
  reserve(n + 1);
  return fac[n] * inv[k] * inv[n - k];
}
inline Modint nHk(ll n, ll k) {
  return nCk(n + k - 1, k);
} // n種類のものから重複を許してk個選ぶ=玉k個と仕切りn-1個

/*
nCk：n!が間に合わないくらい巨大でkが小さいとき、素直に計算すると間に合う
のは1e7以上に組み込んであります auto f = [](ll n, ll k){ if(n<k)return
Modint(0); Modint val(1); k=min(k,n-k); for(ll i=n;i>(n-k);i--)val*=i; for(ll
i=k;i>1;i--)val/=i; return val;
        };
*/

namespace makevectordetail {
template <typename Tp, size_t N>
std::vector<Tp>
make_vector(std::vector<size_t> &sizes,
            typename std::enable_if<(N == 1), Tp const &>::type x) {
  return std::vector<Tp>(sizes[0], x);
}
template <typename Tp, size_t N>
auto make_vector(std::vector<size_t> &sizes,
                 typename std::enable_if<(N > 1), Tp const &>::type x) {
  size_t size = sizes[N - 1];
  sizes.pop_back();
  return std::vector<decltype(make_vector<Tp, N - 1>(sizes, x))>(
      size, make_vector<Tp, N - 1>(sizes, x));
}
} // namespace makevectordetail
template <typename Tp, typename sizetype, size_t N>
auto make_vector(sizetype const (&sizes)[N], Tp const &x = Tp()) {
  std::vector<size_t> s(N);
  for (size_t i = 0; i < N; ++i)
    s[i] = sizes[N - i - 1];
  return makevectordetail::make_vector<Tp, N>(s, x);
}
// vector<vector<vector<ll>>> dp = make_vector<ll>({1, 2, 3}, 0LL);
/*-----8<-----library-----8<-----*/

void solve() {
  ll A, B, C, D;
  cin >> A >> B >> C >> D;

  using dptype = Modint;
  // vector<vector<vector<Modint>>> dp = make_vector<Modint>({C+1, D+1, 3LL},
  // 0); vector<vector<vector<ll>>> checked = make_vector<ll>({C+1, D+1, 3LL},
  // false);
  vector<vector<vector<Modint>>> dp(
      C + 1, vector<vector<Modint>>(D + 1, vector<Modint>(3, 0)));
  vector<vector<vector<bool>>> checked(
      C + 1, vector<vector<bool>>(D + 1, vector<bool>(3, false)));

  // c 最上段の黒マス　0:黒マスが0　1:黒マスが1 2:黒マスが複数
  auto f = [&](auto &&f, ll x, ll y, ll c) -> dptype {
    if (x == A && y == B)
      return (c == 0) ? 1 : 0;
    if (x < A || y < B)
      return 0;
    if (checked[x][y][c])
      return dp[x][y][c];

    dptype ans = 0;
    if (x == A) {
      if (c == 0) {
        dptype t = f(f, x, y - 1, 0) * (x - 1);
        ans = t;
      } else if (c == 1) {
        dptype t = f(f, x, y - 1, 0);
        dptype s = f(f, x, y - 1, 1) * (x - 1);
        ans = t + s;
      } else if (c == 2) {
        dptype t = f(f, x, y - 1, 1);
        dptype s = f(f, x, y - 1, 2) * x;
        ans = t + s;
      }
    } else if (y == B) {
      if (c == 0) {
        ;
      } else if (c == 1) {
        dptype t = f(f, x - 1, y, 1) * y;
        ans = t;
        if (x == A + 1)
          ans += y;
      } else if (c == 2) {
        ;
      }
    } else if (c == 0) {
      dptype t = f(f, x, y - 1, 0) * (x - 1);
      ans = t;
    } else if (c == 1) {
      dptype t = f(f, x, y - 1, 0);
      // dptype s=f(f,x,y-1,1)*(x-1);
      dptype u = 0;
      rep(i, 3) u += f(f, x - 1, y, i) * (y);
      ans = t + u;
    } else if (c == 2) {
      dptype t = f(f, x, y - 1, 1);
      dptype s = f(f, x, y - 1, 2) * x;
      ans = t + s;
    }

    checked[x][y][c] = true;
    return dp[x][y][c] = ans;
  };
  dptype ans = 0;
  rep(i, 3) ans += f(f, C, D, i);
  debug(dp);
  p(ans);
}

// https://atcoder.jp/contests/agc046/tasks/agc046_b
signed main() {
  solve();
  return 0;
}