import sys input = lambda: sys.stdin.readline().rstrip() # 素因数分解 # https://qiita.com/t_fuki/items/7cd50de54d3c5d063b4a # verify問: https://onlinejudge.u-aizu.ac.jp/courses/library/6/NTL/1/NTL_1_A from math import gcd from random import randrange from collections import Counter def isPrime(n): '''ミラーラビンで判定するやつ O(logN)くらい''' if n == 2: return True if n == 1 or n%2 == 0: return False m = n - 1 lsb = m & -m s = lsb.bit_length()-1 d = m // lsb test_numbers = [2, 325, 9375, 28178, 450775, 9780504, 1795265022] for a in test_numbers: a %= n if a == 0: return True x = pow(a,d,n) if x == 1: continue r = 0 while x != m: x = pow(x,2,n) r += 1 if x == 1 or r == s: return False return True # https://qiita.com/t_fuki/items/7cd50de54d3c5d063b4a を非再帰で書き換えたもの # https://judge.yosupo.jp/submission/124476 (Anonymousに爆速にされてた) def getFactorize(N): '''ポラードロー法で取得するやつ O(N^0.25)くらい Returns: Counter({素因数:個数})''' res = Counter() c = 0 while N & 1 == 0: c += 1 N >>= 1 res[2] = c for d in range(3, 314, 2): # 10**5くらいまでは試し割りが速い if N % d == 0: c = 0 while N % d == 0: c += 1 N //= d res[d] = c while N > 1: n = N while not isPrime(n): # ブレントの循環検出 m = int(n**0.125)+1 # gcdまとめる回数 while True: c = randrange(n) y = randrange(n) g = q = r = 1 # g:gcdの結果 q:(x-y)の積 r: while g == 1: x = y for _ in range(r >> 1, (3 * r) >> 2):# gcdしない部分 y = (y*y + c) % n for k in range((3 * r) >> 2, r, m): ys = y # ここから考え直すやつ for _ in range(min(m, r-k)): # m個ずつまとめてgcd y = (y*y + c) % n q = q * (x - y) % n g = gcd(q, n) if g != 1: break r <<= 1 # gcd=1なら続行 if g == n: # gcd=nならちょっと戻って境界を探す g = 1 y = ys while g == 1: y = (y*y + c) % n g = gcd(x-y, n) if g != n: # 一瞬でgcd=nになってたらもう一回 break n = g # gを元手にもう一回 素数ならすぐ下へ c = 0 while N % n == 0: c += 1 N //= n res[n] = c return res MOD = 998244353 def main(): # 入力 N, M = map(int, input().split()) # 計算・出力 pf = getFactorize(M) ans = 1 for val in pf.values(): ans *= (pow(val+1, N, MOD) - pow(val, N, MOD)) ans %= MOD print(ans) if __name__ == "__main__": main()