#line 2 "cp-library/src/cp-template.hpp" #include using namespace std; using ll = long long; using ld = long double; using uint = unsigned int; using ull = unsigned long long; using i32 = int; using u32 = unsigned int; using i64 = long long; using u64 = unsigned long long; using i128 = __int128_t; template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; } template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; } template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y : x / y); } template < class T, class U > T floor(T x, U y) { return (x > 0 ? x / y : (x - y + 1) / y); } int popcnt(i32 x) { return __builtin_popcount(x); } int popcnt(u32 x) { return __builtin_popcount(x); } int popcnt(i64 x) { return __builtin_popcountll(x); } int popcnt(u64 x) { return __builtin_popcountll(x); } #line 2 "cp-library/src/utility/rep_itr.hpp" template < class T > struct itr_rep { T i, d; constexpr itr_rep(const T i) noexcept : i(i), d(1) {} constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {} void operator++() noexcept { i += d; } constexpr int operator*() const noexcept { return i; } constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; } }; template < class T > struct rep { const itr_rep< T > s, t; constexpr rep(const T t) noexcept : s(0), t(t) {} constexpr rep(const T s, const T t) noexcept : s(s), t(t) {} constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {} constexpr auto begin() const noexcept { return s; } constexpr auto end () const noexcept { return t; } }; template < class T > struct revrep { const itr_rep < T > s, t; constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {} constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {} constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {} constexpr auto begin() const noexcept { return s; } constexpr auto end () const noexcept { return t; } }; #line 3 "cp-library/src/utility/io.hpp" /* 128bit integer */ istream& operator>>(istream& is, i128& x) { std::string s; is >> s; int pm = (s[0] == '-'); x = 0; for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0'); if(pm) x *= -1; return is; } ostream& operator<<(ostream& os, const i128& x) { if(x == 0) return os << '0'; i128 y = x; if(y < 0) { os << '-'; y *= -1; } std::vector ny; while(y > 0) { ny.push_back(y % 10); y /= 10; } for(int i : revrep(ny.size())) os << ny[i]; return os; } template < class S, class T > istream& operator>>(istream& is, std::pair< S, T >& x) { is >> x.first >> x.second; return is; } template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; } namespace scanner { struct sca { template < class T > operator T() { T s; std::cin >> s; return s; } }; struct vec { int n; vec(int n) : n(n) {} template < class T > operator std::vector< T >() { std::vector< T > v(n); for(T& x : v) std::cin >> x; return v; } }; struct mat { int h, w; mat(int h, int w) : h(h), w(w) {} template < class T > operator std::vector< std::vector< T > >() { std::vector m(h, std::vector< T >(w)); for(std::vector< T >& v : m) for(T& x : v) std::cin >> x; return m; } }; struct speedup { speedup() { std::cin.tie(0); std::ios::sync_with_stdio(0); } } speedup_instance; } scanner::sca in() { return scanner::sca(); } scanner::vec in(int n) { return scanner::vec(n); } scanner::mat in(int h, int w) { return scanner::mat(h, w); } namespace printer { void precision(int d) { std::cout << std::fixed << std::setprecision(d); } void flush() { std::cout.flush(); } } template < class T > ostream& operator<<(ostream& os, const std::vector< T > a) { int n = a.size(); for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; } return os; } int print() { std::cout << '\n'; return 0; } template < class head, class... tail > int print(head&& h, tail&&... t) { std::cout << h; if(sizeof...(tail)) std::cout << ' '; return print(std::forward(t)...); } template < class T > int print_n(const std::vector< T > a) { int n = a.size(); for(int i : rep(n)) std::cout << a[i] << "\n"; return 0; } #line 2 "cp-library/src/utility/key_val.hpp" template < class K, class V > struct key_val { K key; V val; key_val() {} key_val(K key, V val) : key(key), val(val) {} template < std::size_t Index > std::tuple_element_t< Index, key_val >& get() { if constexpr (Index == 0) return key; if constexpr (Index == 1) return val; } }; namespace std { template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {}; template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; }; template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; }; } #line 2 "cp-library/src/utility/vec_op.hpp" template < class T > key_val< int, T > max_of(const vector< T >& a) { int i = std::max_element(a.begin(), a.end()) - a.begin(); return {i, a[i]}; } template < class T > key_val< int, T > min_of(const vector< T >& a) { int i = std::min_element(a.begin(), a.end()) - a.begin(); return {i, a[i]}; } template < class S, class T > S sum_of(const vector< T >& a) { S sum = 0; for(const T x : a) sum += x; return sum; } template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) { vector< S > res(R - L, S(0)); for(const T x : a) res[x - L] += 1; return res; } template < class S, class T > struct prefix_sum { vector< S > s; prefix_sum(const vector< T >& a) : s(a) { s.insert(s.begin(), S(0)); for(int i : rep(a.size())) s[i + 1] += s[i]; } // [L, R) S sum(int L, int R) { return s[R] - s[L]; } }; #line 3 "cp-library/src/utility/heap.hpp" template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >; template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >; #line 27 "cp-library/src/cp-template.hpp" #line 1 "cp-library/src/algorithm/bin_search.hpp" template < class T, class F > T bin_search(T ok, T ng, F f) { while(abs(ng - ok) > 1) { T mid = (ok + ng) / 2; (f(mid) ? ok : ng) = mid; } return ok; } template < class T, class F > T bin_search_real(T ok, T ng, F f, int step = 80) { while(step--) { T mid = (ok + ng) / 2; (f(mid) ? ok : ng) = mid; } return ok; } #line 2 "cp-library/src/algorithm/argsort.hpp" template < class T > std::vector< int > argsort(const std::vector< T > &a) { std::vector< int > ids((int)a.size()); std::iota(ids.begin(), ids.end(), 0); std::sort(ids.begin(), ids.end(), [&](int i, int j) { return a[i] < a[j] || (a[i] == a[j] && i < j); }); return ids; } #line 1 "macro.hpp" namespace macro { using size_type = int; template < class container > void sort(container& a) { std::sort(std:: begin(a), std:: end(a)); } template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); } template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); } template < class container > void unique(container& a) { std::sort(std::begin(a), std::end(a)); a.erase(std::unique(std::begin(a), std::end(a)), std::end(a)); } template < class container > container sorted(const container& a) { container b = a; sort(b); return std::move(b); } template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); } template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); } template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); } template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); } template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); } const std::vector> dir4 = { {+1, 0}, {-1, 0}, { 0, +1}, { 0, -1} }; const std::vector> dir8 = { {-1, -1}, {-1, 0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1, 0}, {+1, +1} }; #ifdef _DEBUG #define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl #else #define debug(x) #endif template < class container > void concat(container& a, const container& b) { a.insert(std::end(a), std::begin(b), std::end(b)); } std::vector iota(const size_type n) { std::vector I(n); std::iota(std::begin(I), std::end(I), 0); return I; } template < class container > std::vector sort_idx(const container& a) { const size_type n = a.size(); std::vector I = iota(n); std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); }); return I; } template < class container, class compare > std::vector sort_idx(const container& a, const compare& cmp) { const size_type n = a.size(); std::vector I = iota(n); std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); }); return std::move(I); } struct grid { using size_type = int; size_type H, W; grid(const size_type H, const size_type W) : H(H), W(W) {} bool contains(const size_type i, const size_type j) { return 0 <= i and i < H and 0 <= j and j < W; } }; using f64 = long double; template < class T > vector< T >& operator++(vector< T >& a) { for(T& x : a) x++; return a; } template < class T > vector< T >& operator--(vector< T >& a) { for(T& x : a) x--; return a; } template < class T > vector< T > operator++(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x++; return res; } template < class T > vector< T > operator--(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x--; return res; } } // namespace macro using namespace macro; #line 2 "cp-library/src/number/modint.hpp" struct modinfo { uint mod, root, isprime; }; template < modinfo const &ref > struct modint { static constexpr uint const &mod = ref.mod; static constexpr uint const &root = ref.root; static constexpr uint const &isprime = ref.isprime; uint v = 0; constexpr modint& s(uint v) { this->v = v < mod ? v : v - mod; return *this; } constexpr modint(ll v = 0) { s(v % mod + mod); } modint operator-() const { return modint() - *this; } modint& operator+=(const modint& rhs) { return s(v + rhs.v); } modint& operator-=(const modint& rhs) { return s(v + mod - rhs.v); } modint& operator*=(const modint& rhs) { v = ull(v) * rhs.v % mod; return *this; } modint& operator/=(const modint& rhs) { return *this *= inv(rhs); } modint operator+(const modint& rhs) const { return modint(*this) += rhs; } modint operator-(const modint& rhs) const { return modint(*this) -= rhs; } modint operator*(const modint& rhs) const { return modint(*this) *= rhs; } modint operator/(const modint& rhs) const { return modint(*this) /= rhs; } friend modint pow(modint x, ll n) { modint res(1); while(n > 0) { if(n & 1) res *= x; x *= x; n >>= 1; } return res; } friend modint inv(modint v) { if(isprime) { return pow(v, mod - 2); } else { ll a = v.v, b = modint::mod, x = 1, y = 0, t; while(b > 0) { t = a / b; swap(a -= t * b, b); swap(x -= t * y, y); } return modint(x); } } friend modint operator+(int x, const modint& y) { return modint(x) + y; } friend modint operator-(int x, const modint& y) { return modint(x) - y; } friend modint operator*(int x, const modint& y) { return modint(x) * y; } friend modint operator/(int x, const modint& y) { return modint(x) / y; } friend istream& operator>>(istream& is, modint& m) { ll x; is >> x; m = modint(x); return is; } friend ostream& operator<<(ostream& os, const modint& m) { return os << m.v; } bool operator==(const modint& r) const { return v == r.v; } bool operator!=(const modint& r) const { return v != r.v; } static uint get_mod() { return mod; } static int is_prime() { return isprime; } }; constexpr modinfo base998244353 { 998244353, 3, 1 }; constexpr modinfo base1000000007 { 1000000007, 0, 1 }; using mint998244353 = modint< base998244353 >; using mint1000000007 = modint< base1000000007 >; #line 3 "cp-library/src/number/binom_mod.hpp" template < class mint > mint fact(int n) { assert(0 <= n); assert(mint::is_prime()); static const uint mod = mint::get_mod(); static std::vector data = {1, 1}; while(int(data.size()) <= n) { int i = data.size(); data.push_back(data.back() * i); } return data[n]; } template < class mint > mint inv(int n) { assert(0 <= n); assert(mint::is_prime()); static const uint mod = mint::get_mod(); static std::vector data = {1, 1}; while(int(data.size()) <= n) { int i = data.size(); data.push_back(- data[mod % i] * (mod / i)); } return data[n]; } template < class mint > mint fact_inv(int n) { assert(0 <= n); assert(mint::is_prime()); static const uint mod = mint::get_mod(); static std::vector data = {1, 1}; while(int(data.size()) <= n) { int i = data.size(); data.push_back(data.back() * inv(i)); } return data[n]; } template < class mint > mint comb(int n, int k) { if(k < 0 or n < k) return 0; return fact(n) * fact_inv(k) * fact_inv(n - k); } template < class mint > mint perm(int n, int k) { return fact(n) * fact_inv(n - k); } template < class mint > mint homo(int n, int k) { return comb(n + k - 1, k); } template < class mint > struct power { mint a; std::vector data = {1}; power() {} power(const mint a) : a(a) {} // a^n mint get(const int n) { assert(0 <= n); while(int(data.size()) <= n) data.push_back(data.back() * a); return data[n]; } }; #line 5 "C.cpp" // https://judge.yosupo.jp/submission/129637 template struct LazyMontgomeryModInt { using mint = LazyMontgomeryModInt; using i32 = int32_t; using u32 = uint32_t; using u64 = uint64_t; static constexpr u32 get_r() { u32 ret = mod; for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret; return ret; } static constexpr u32 r = get_r(); static constexpr u32 n2 = -u64(mod) % mod; static_assert(r * mod == 1, "invalid, r * mod != 1"); static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30"); static_assert((mod & 1) == 1, "invalid, mod % 2 == 0"); u32 a; constexpr LazyMontgomeryModInt() : a(0) {} constexpr LazyMontgomeryModInt(const int64_t &b) : a(reduce(u64(b % mod + mod) * n2)){}; static constexpr u32 reduce(const u64 &b) { return (b + u64(u32(b) * u32(-r)) * mod) >> 32; } constexpr mint &operator+=(const mint &b) { if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod; return *this; } constexpr mint &operator-=(const mint &b) { if (i32(a -= b.a) < 0) a += 2 * mod; return *this; } constexpr mint &operator*=(const mint &b) { a = reduce(u64(a) * b.a); return *this; } constexpr mint &operator/=(const mint &b) { *this *= b.inverse(); return *this; } constexpr mint operator+(const mint &b) const { return mint(*this) += b; } constexpr mint operator-(const mint &b) const { return mint(*this) -= b; } constexpr mint operator*(const mint &b) const { return mint(*this) *= b; } constexpr mint operator/(const mint &b) const { return mint(*this) /= b; } constexpr bool operator==(const mint &b) const { return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a); } constexpr bool operator!=(const mint &b) const { return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a); } constexpr mint operator-() const { return mint() - mint(*this); } constexpr mint pow(u64 n) const { mint ret(1), mul(*this); while (n > 0) { if (n & 1) ret *= mul; mul *= mul; n >>= 1; } return ret; } constexpr mint inverse() const { return pow(mod - 2); } friend ostream &operator<<(ostream &os, const mint &b) { return os << b.get(); } friend istream &operator>>(istream &is, mint &b) { int64_t t; is >> t; b = LazyMontgomeryModInt(t); return (is); } constexpr u32 get() const { u32 ret = reduce(a); return ret >= mod ? ret - mod : ret; } static constexpr u32 get_mod() { return mod; } }; using namespace std; template struct Binomial { vector fac_, finv_, inv_; Binomial(int MAX) : fac_(MAX + 10), finv_(MAX + 10), inv_(MAX + 10) { MAX += 9; fac_[0] = finv_[0] = inv_[0] = 1; for (int i = 1; i <= MAX; i++) fac_[i] = fac_[i - 1] * i; finv_[MAX] = fac_[MAX].inverse(); for (int i = MAX - 1; i > 0; i--) finv_[i] = finv_[i + 1] * (i + 1); for (int i = 1; i <= MAX; i++) inv_[i] = finv_[i] * fac_[i - 1]; } inline T fac(int i) const { return fac_[i]; } inline T finv(int i) const { return finv_[i]; } inline T inv(int i) const { return inv_[i]; } T C(int n, int r) const { if (n < r || r < 0) return T(0); return fac_[n] * finv_[n - r] * finv_[r]; } T C_naive(int n, int r) const { if (n < r || r < 0) return T(0); T ret = 1; for (T i = 1; i <= r; i += T(1)) { ret *= n--; ret *= i.inverse(); } return ret; } T P(int n, int r) const { if (n < r || r < 0) return T(0); return fac_[n] * finv_[n - r]; } T H(int n, int r) const { if (n < 0 || r < 0) return (0); return r == 0 ? 1 : C(n + r - 1, r); } }; // given y(x=0)...y(k) , return y(x) template mint lagrange_interpolation(const vector& y, long long x, const Binomial& C) { int N = (int)y.size() - 1; if (x <= N) return y[x]; mint ret = 0; vector dp(N + 1, 1), pd(N + 1, 1); mint a = x, one = 1; for (int i = 0; i < N; i++) dp[i + 1] = dp[i] * a, a -= one; for (int i = N; i > 0; i--) pd[i - 1] = pd[i] * a, a += one; for (int i = 0; i <= N; i++) { mint tmp = y[i] * dp[i] * pd[i] * C.finv(i) * C.finv(N - i); ret += ((N - i) & 1) ? -tmp : tmp; } return ret; } // given f(0)...f(k) (deg(f) = k) // return \sum_{i=0...n-1} a^i f(i) template mint sum_of_exp(const vector& f, mint a, long long n, const Binomial& C) { if (n == 0) return mint(0); if (a == mint(0)) return f[0]; if (a == mint(1)) { vector g(f.size() + 1, mint(0)); for (int i = 1; i < (int)g.size(); i++) g[i] = g[i - 1] + f[i - 1]; return lagrange_interpolation(g, n, C); } int K = f.size() - 1; vector g(f.size()); mint buf = 1; for (int i = 0; i < (int)g.size(); i++) g[i] = f[i] * buf, buf *= a; for (int i = 1; i < (int)g.size(); i++) g[i] += g[i - 1]; mint c = 0, buf2 = 1; for (int i = 0; i <= K; i++) c += C.C(K + 1, i) * buf2 * g[K - i], buf2 *= -a; c /= (-a + 1).pow(K + 1); mint buf3 = 1, ia = a.inverse(); for (int i = 0; i < (int)g.size(); i++) g[i] = (g[i] - c) * buf3, buf3 *= ia; mint tn = lagrange_interpolation(g, n - 1, C); return tn * a.pow(n - 1) + c; } // given f(0)...f(k) (deg(f) = k) // return \sum_{i=0...infty} a^i f(i) template mint sum_of_exp_limit(const vector& f, mint a, const Binomial& C) { if (a == mint(0)) return f[0]; int K = f.size() - 1; vector g(f.size()); mint buf = 1; for (int i = 0; i < (int)g.size(); i++) g[i] = f[i] * buf, buf *= a; for (int i = 1; i < (int)g.size(); i++) g[i] += g[i - 1]; mint c = 0, buf2 = 1; for (int i = 0; i <= K; i++) c += C.C(K + 1, i) * buf2 * g[K - i], buf2 *= -a; c /= (-a + 1).pow(K + 1); return c; } template vector exp_enamurate(int p, int n) { vector f(n + 1, mint(0)); if (!p) { f[0] = 1; return std::move(f); } f[1] = 1; vector sieve(n + 1, false); vector ps; for (int i = 2; i <= n; i++) { if (!sieve[i]) { f[i] = mint(i).pow(p); ps.push_back(i); } for (int j = 0; j < (int)ps.size() && i * ps[j] <= n; j++) { sieve[i * ps[j]] = 1; f[i * ps[j]] = f[i] * f[ps[j]]; if (i % ps[j] == 0) break; } } return std::move(f); } template mint sum_of_exp2(int d, mint r, long long n, const Binomial& C) { vector f = exp_enamurate(d, d); return sum_of_exp(f, r, n, C); } template mint sum_of_exp_limit2(int d, mint r, const Binomial& C) { vector f = exp_enamurate(d, d); return sum_of_exp_limit(f, r, C); } using mint = LazyMontgomeryModInt<998244353>; Binomial C(10001000); mint solve(i64 r, i64 d, i64 n) { return sum_of_exp2(d, r, n, C).get(); } int main() { int N = in(), K = in(); mint ans = 0; ans += solve(1, K, N) * N - solve(1, K + 1, N); print(ans * C.fac(N - 1) * 2); }