// #pragma GCC optimize("O3,unroll-loops") // #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include "bits/stdc++.h" using namespace std; using ll = long long int; mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count()); /** * Integers modulo p, where p is a prime * Source: Aeren (modified from tourist?) * Modmul for 64-bit mod from kactl:ModMulLL * Works with p < 7.2e18 with x87 80-bit long double, and p < 2^52 ~ 4.5e12 with 64-bit */ template struct Z_p{ using Type = typename decay::type; static vector MOD_INV; constexpr Z_p(): value(){ } template Z_p(const U &x){ value = normalize(x); } template static Type normalize(const U &x){ Type v; if(-mod() <= x && x < mod()) v = static_cast(x); else v = static_cast(x % mod()); if(v < 0) v += mod(); return v; } const Type& operator()() const{ return value; } template explicit operator U() const{ return static_cast(value); } constexpr static Type mod(){ return T::value; } Z_p &operator+=(const Z_p &otr){ if((value += otr.value) >= mod()) value -= mod(); return *this; } Z_p &operator-=(const Z_p &otr){ if((value -= otr.value) < 0) value += mod(); return *this; } template Z_p &operator+=(const U &otr){ return *this += Z_p(otr); } template Z_p &operator-=(const U &otr){ return *this -= Z_p(otr); } Z_p &operator++(){ return *this += 1; } Z_p &operator--(){ return *this -= 1; } Z_p operator++(int){ Z_p result(*this); *this += 1; return result; } Z_p operator--(int){ Z_p result(*this); *this -= 1; return result; } Z_p operator-() const{ return Z_p(-value); } template typename enable_if::Type, int>::value, Z_p>::type &operator*=(const Z_p& rhs){ #ifdef _WIN32 uint64_t x = static_cast(value) * static_cast(rhs.value); uint32_t xh = static_cast(x >> 32), xl = static_cast(x), d, m; asm( "divl %4; \n\t" : "=a" (d), "=d" (m) : "d" (xh), "a" (xl), "r" (mod()) ); value = m; #else value = normalize(static_cast(value) * static_cast(rhs.value)); #endif return *this; } template typename enable_if::Type, int64_t>::value, Z_p>::type &operator*=(const Z_p &rhs){ uint64_t ret = static_cast(value) * static_cast(rhs.value) - static_cast(mod()) * static_cast(1.L / static_cast(mod()) * static_cast(value) * static_cast(rhs.value)); value = normalize(static_cast(ret + static_cast(mod()) * (ret < 0) - static_cast(mod()) * (ret >= static_cast(mod())))); return *this; } template typename enable_if::Type>::value, Z_p>::type &operator*=(const Z_p &rhs){ value = normalize(value * rhs.value); return *this; } template Z_p &operator^=(U e){ if(e < 0) *this = 1 / *this, e = -e; Z_p res = 1; for(; e; *this *= *this, e >>= 1) if(e & 1) res *= *this; return *this = res; } template Z_p operator^(U e) const{ return Z_p(*this) ^= e; } Z_p &operator/=(const Z_p &otr){ Type a = otr.value, m = mod(), u = 0, v = 1; if(a < (int)MOD_INV.size()) return *this *= MOD_INV[a]; while(a){ Type t = m / a; m -= t * a; swap(a, m); u -= t * v; swap(u, v); } assert(m == 1); return *this *= u; } template friend const Z_p &abs(const Z_p &v){ return v; } Type value; }; template bool operator==(const Z_p &lhs, const Z_p &rhs){ return lhs.value == rhs.value; } template::value>::type* = nullptr> bool operator==(const Z_p& lhs, U rhs){ return lhs == Z_p(rhs); } template::value>::type* = nullptr> bool operator==(U lhs, const Z_p &rhs){ return Z_p(lhs) == rhs; } template bool operator!=(const Z_p &lhs, const Z_p &rhs){ return !(lhs == rhs); } template::value>::type* = nullptr> bool operator!=(const Z_p &lhs, U rhs){ return !(lhs == rhs); } template::value>::type* = nullptr> bool operator!=(U lhs, const Z_p &rhs){ return !(lhs == rhs); } template bool operator<(const Z_p &lhs, const Z_p &rhs){ return lhs.value < rhs.value; } template bool operator>(const Z_p &lhs, const Z_p &rhs){ return lhs.value > rhs.value; } template bool operator<=(const Z_p &lhs, const Z_p &rhs){ return lhs.value <= rhs.value; } template bool operator>=(const Z_p &lhs, const Z_p &rhs){ return lhs.value >= rhs.value; } template Z_p operator+(const Z_p &lhs, const Z_p &rhs){ return Z_p(lhs) += rhs; } template::value>::type* = nullptr> Z_p operator+(const Z_p &lhs, U rhs){ return Z_p(lhs) += rhs; } template::value>::type* = nullptr> Z_p operator+(U lhs, const Z_p &rhs){ return Z_p(lhs) += rhs; } template Z_p operator-(const Z_p &lhs, const Z_p &rhs){ return Z_p(lhs) -= rhs; } template::value>::type* = nullptr> Z_p operator-(const Z_p& lhs, U rhs){ return Z_p(lhs) -= rhs; } template::value>::type* = nullptr> Z_p operator-(U lhs, const Z_p &rhs){ return Z_p(lhs) -= rhs; } template Z_p operator*(const Z_p &lhs, const Z_p &rhs){ return Z_p(lhs) *= rhs; } template::value>::type* = nullptr> Z_p operator*(const Z_p& lhs, U rhs){ return Z_p(lhs) *= rhs; } template::value>::type* = nullptr> Z_p operator*(U lhs, const Z_p &rhs){ return Z_p(lhs) *= rhs; } template Z_p operator/(const Z_p &lhs, const Z_p &rhs) { return Z_p(lhs) /= rhs; } template::value>::type* = nullptr> Z_p operator/(const Z_p& lhs, U rhs) { return Z_p(lhs) /= rhs; } template::value>::type* = nullptr> Z_p operator/(U lhs, const Z_p &rhs) { return Z_p(lhs) /= rhs; } template istream &operator>>(istream &in, Z_p &number){ typename common_type::Type, int64_t>::type x; in >> x; number.value = Z_p::normalize(x); return in; } template ostream &operator<<(ostream &out, const Z_p &number){ return out << number(); } /* using ModType = int; struct VarMod{ static ModType value; }; ModType VarMod::value; ModType &mod = VarMod::value; using Zp = Z_p; */ // constexpr int mod = 1e9 + 7; // 1000000007 constexpr int mod = (119 << 23) + 1; // 998244353 // constexpr int mod = 1e9 + 9; // 1000000009 using Zp = Z_p::type, mod>>; template vector::Type> Z_p::MOD_INV; template::type, mod>> void precalc_inverse(int SZ){ auto &inv = Z_p::MOD_INV; if(inv.empty()) inv.assign(2, 1); for(; inv.size() <= SZ; ) inv.push_back((mod - 1LL * mod / (int)inv.size() * inv[mod % (int)inv.size()]) % mod); } template vector precalc_power(T base, int SZ){ vector res(SZ + 1, 1); for(auto i = 1; i <= SZ; ++ i) res[i] = res[i - 1] * base; return res; } template vector precalc_factorial(int SZ){ vector res(SZ + 1, 1); res[0] = 1; for(auto i = 1; i <= SZ; ++ i) res[i] = res[i - 1] * i; return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); auto fac = precalc_factorial(600005); auto C = [&] (int n, int r) { if (r < 0 or n < r) return Zp(0); return fac[n] / (fac[r] * fac[n-r]); }; int x, y, z, w; cin >> x >> y >> z >> w; Zp ans = 0; if (z == 0) { // All humans gone -> last is a human // a1 + a2 + ... + ax = y - w, all are >= 0 cout << fac[x] * C(y, w) * fac[y-w] * C(y-w + x - 1, x - 1) << '\n'; } else { cout << fac[y] * C(x, z) * fac[x-z] * C(x-z + y-1, y-1) << '\n'; } // cout << ans << '\n'; }