#include <bits/stdc++.h>
#define rep(i, n) for (rint i = 1; i <= int(n); i ++)
#define re0(i, n) for (rint i = 0; i < (int) n; i ++)
#define travel(i, u) for (rint i = head[u]; i; i = e[i].nxt)
#define rint register int
using namespace std;

typedef long long lo;

template<typename tp> inline void read(tp &x) {
    x = 0; char c = getchar(); int f = 0;
    for (; c < '0' || c > '9'; f |= c == '-', c = getchar());
    for (; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
    if (f) x = -x;
}

namespace {
    const int mo = 998244353;
    const int G = 3;
    inline int add(int x, int y) { x += y; return x >= mo ? x - mo : x; }
    inline int sub(int x, int y) { x -= y; return x < 0 ? x + mo : x; }
    inline int mul(int x, int y) { return (lo) x * y % mo; }
    inline int power(int a, lo k = mo - 2) {
		int ans = 1;
		for (; k; k >>= 1, a = mul(a, a))
			if (k & 1) ans = mul(ans, a);
		return ans;
    }
    inline int getind(int x) {
		unordered_map <int, int> mp;
		int K = sqrt(mo), ix = power(x);
		for (int t = 1, k = 0; k <= K; k++, t = mul(t, G))
			mp[t] = k;
		int p = power(G, K);
		for (int t = p, k = 1; k <= K; k++, t = mul(t, p))
			if (mp.count(mul(t, ix))) {
				return k * K - mp[mul(t, ix)];
			}
		assert(0);
    }
    inline int getSqrt(int x) {
		int t = power(G, getind(x) / 2);
		return min(t, mo - t);
    }
}
typedef unsigned long long ul;
typedef vector <int> poly;
#define pb push_back

const int N = (1 << 20) + 233;
namespace FFT {
    int fft_n, fft_l, rev[N];
    ul *data[30], wn[N << 1];
	
    inline void prepare(int n) {
		fft_n = 1; fft_l = -1;
		while (fft_n < n) fft_n <<= 1, ++fft_l;
		re0 (i, fft_n) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << fft_l);
	ul *cur = wn;
	for (int cn = 2, step = 0; cn <= fft_n; cn <<= 1, ++step) {
	    data[step] = cur;
	    ul t = power(G, (mo - 1) / cn), w = 1;
	    re0 (k, cn) *cur++ = w, w = w * t % mo;
	}
    }
    inline void dft(ul *a, int n) {
	re0 (i, n) if (i < rev[i]) swap(a[i], a[rev[i]]);
	for (int l = 2, step = 0; l <= fft_n; l <<= 1, ++step) 
	    for (int i = 0, m = l >> 1; i < fft_n; i += l) {
		ul *l = a + i, *r = a + i + m, *w = data[step];
		for (int k = 0; k < m; k++, ++l, ++r, ++w) {
		    ul y = *r * *w % mo;
		    *r = *l + mo - y; *l += y;
		}
	    }
	re0 (i, n) a[i] %= mo;
    }
    inline void idft(ul *a, int n) {
	dft(a, n);
	reverse(a + 1, a + n);
	int invn = power(n);
	re0 (i, n) a[i] = mul(a[i], invn);
    }
    poly realmain(poly a, poly b, int op = 1) {
	static ul x[N], y[N];
	int n = a.size(), m = b.size();
	prepare(n * op + m - 1);
	re0 (i, fft_n) {
	    x[i] = i < n ? a[i] : 0;
	    y[i] = i < m ? b[i] : 0;
	}
	dft(x, fft_n); dft(y, fft_n);
	re0 (i, fft_n) x[i] = mul(op == 2 ? x[i] : 1, mul(x[i], y[i]));
	idft(x, fft_n);
	poly ans(n + m - 1, 0);
	re0 (i, ans.size()) ans[i] = x[i];
	return ans;
    }
}

poly K(poly a, int l) { a.resize(l); return a; }
poly rev(poly a) { reverse(a.begin(), a.end()); return a; }

inline void ovo(poly a) {
    cout << "(";
    re0 (i, a.size()) cout << a[i] << ",)"[i + 1 == a.size()];
    cout << "\n";
}

poly operator + (poly a, poly b) {
    if (a.size() < b.size()) a.resize(b.size());
    re0 (i, b.size()) a[i] = add(a[i], b[i]);
    return a;
}

poly operator - (poly a, poly b) {
    if (a.size() < b.size()) a.resize(b.size());
    re0 (i, b.size()) a[i] = sub(a[i], b[i]);
    return a;
}

poly operator * (poly a, poly b) {
    if (a.size() + b.size() < 128) {
	if (!a.size() && !b.size()) return a;
	poly ans(a.size() + b.size() - 1, 0);
	re0 (i, a.size()) re0 (j, b.size()) ans[i + j] = add(ans[i + j], mul(a[i], b[j]));
	return ans;
    }
    return FFT::realmain(a, b);
}

poly operator * (poly a, int k) {
    re0 (i, a.size()) a[i] = mul(a[i], k);
    return a;
}

poly Der(poly a) {
    if (!a.size()) return poly(1, 0);
    poly t(a.size() - 1, 0);
    rep (i, t.size()) t[i - 1] = mul(a[i], i);
    return t;
}

poly Int(poly a) {
    static int inv[N];
    inv[0] = inv[1] = 1;
    for (int i = 2; i <= (int) a.size(); i++)
	inv[i] = mul(mo - mo / i, inv[mo % i]);
    poly t(a.size() + 1, 0);
    rep (i, a.size()) t[i] = mul(a[i - 1], inv[i]);
    return t;
}

poly Inv(poly a, int n) {
    a.resize(n);
    if (n == 1) return poly(1, power(a[0]));
    poly b = Inv(a, (n + 1) >> 1); 
    return K(b * 2 - K(FFT::realmain(b, a, 2), n), n);
}

poly Ln(poly a, int n) {
    return Int(K(Der(a) * Inv(a, n), n - 1));
}

poly Exp(poly a, int n) {
    a.resize(n);
    if (n == 1) return assert(a[0] == 0), poly(1, 1);
    poly b = Exp(a, (n + 1) >> 1);
    return K(b * (a + poly(1, 1) - Ln(b, n)), n);
}

poly Sqrt(poly a, int n) {
    a.resize(n);
    if (n == 1) return poly(1, getSqrt(a[0]));
    poly b = Sqrt(a, (n + 1) >> 1);
    return (b + K(a * Inv(b, n), n)) * power(2);
}

poly power(poly a, lo k) {
    int n = a.size();
    int p = 0;
    while (p < a.size() && !a[p]) ++p;
    if (p == a.size() || p * k > n) return poly(n, 0);
    poly b(a.size() - p, 0);
    int tmp = a[p], t = power(a[p]);
    re0 (i, b.size()) b[i] = mul(t, a[i + p]);
    b = Exp(Ln(b, n - p) * k, n - p);
    b = rev(b); b.resize(b.size() + p * k); b = rev(b);
    return K(b * power(tmp, k), n);
}

int fac[N], ifac[N];
inline int C(int n, int m) {
	return n < m ? 0 : mul(fac[n], mul(ifac[m], ifac[n - m]));
}

int main(void) {
	int n, m;
	read(n); read(m);
	fac[0] = 1; rep (i, m) fac[i] = mul(fac[i - 1], i);
	ifac[m] = power(fac[m]); for (int i = m - 1; i >= 0; i--) ifac[i] = mul(ifac[i + 1], i + 1);
	poly dp(m + 1, 0);
	for (int k = 0; k <= m; k++) {
		dp[k] = mul(m + 1 - k, ifac[k]);
	}
	dp = power(dp, n);
	int ans = 0;
	for (int i = 0; i <= m; i++) {
		ans = add(ans, mul(dp[i], mul(fac[m], ifac[m - i])));
	}
	cout << ans << "\n";
}


Measured memory_bytes: 68516