MOD = 998244353 # : 119*2**23+1 K,M,W = 119, 23, 31 # W : 2のM乗根 class NTT: def __init__(self): # ws[i] = 1の2^i乗根  (31**(2**23) = 1 mod 998244353) # 内部で pow(W, 2**i, MOD) を計算 self.ws = [pow(W, 1 << i, MOD) for i in range(M, -1, -1)] # inverse of ws self.iws = [pow(w, MOD - 2, MOD) for w in self.ws] def polymul_ntt(self, f, g): nf = len(f) ng = len(g) m = nf + ng - 1 n = 2**(m - 1).bit_length() # 0-padding # C++版とは異なり、ここでMODをとる f = [x % MOD for x in f] + [0] * (n - nf) g = [x % MOD for x in g] + [0] * (n - ng) self.ntt(f) self.ntt(g) for i in range(n): f[i] = f[i] * g[i] % MOD self.intt(f) return f[:m] def ntt(self, A): if len(A) == 1: return n = len(A) k = n.bit_length() - 1 r = 1 << (k - 1) # self.ws[k:0:-1] のスライスは [ws[k], ws[k-1], ..., ws[1]] を意味する for w in self.ws[k:0:-1]: for l in range(0, n, 2 * r): wi = 1 for i in range(r): # Gentleman-Sade butterfly A[l + i], A[l + i + r] = (A[l + i] + A[l + i + r]) % MOD, (A[l + i] - A[l + i + r]) * wi % MOD wi = wi * w % MOD r = r // 2 def intt(self, A): if len(A) == 1: return n = len(A) k = (n - 1).bit_length() r = 1 # self.iws[1:k+1] のスライスは [iws[1], iws[2], ..., iws[k]] を意味する for w in self.iws[1:k + 1]: for l in range(0, n, 2 * r): wi = 1 for i in range(r): # Colley-Tukey butterfly A[l + i], A[l + i + r] = (A[l + i] + A[l + i + r] * wi) % MOD, (A[l + i] - A[l + i + r] * wi) % MOD wi = wi * w % MOD r = r * 2 ni = pow(n, MOD - 2, MOD) for i in range(n): A[i] = A[i] * ni % MOD def main(): ntt_solver = NTT() n,m = map(int, input().split()) f = [1, 1] for i in range(n): fx = f.copy() fy = f.copy() fy[0] = 0 f = ntt_solver.polymul_ntt(fx, fy) f[0] = 1 ans = f[2**n-m] for i in range(1, m+1): ans = ans * i % MOD for i in range(1, 2**n - m + 1): ans = ans * i % MOD print(ans) if __name__ == "__main__": main()