#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string(string(s)); }
string to_string(bool b) { return to_string(int(b)); }
string to_string(vector<bool>::reference b) { return to_string(int(b)); }
string to_string(char b) { return "'" + string(1, b) + "'"; }
template <typename A, typename B>
string to_string(pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A>
string to_string(A v) {
	string res = "{";
	for (const auto& x : v) res += (res == "{" ? "" : ", ") + to_string(x);
	return res + "}";
}
void debug() { cerr << endl; }
template <typename Head, typename... Tail>
void debug(Head H, Tail... T) {
	cerr << " " << to_string(H);
	debug(T...);
}
#define db(...) cerr << "[" << #__VA_ARGS__ << "]:", debug(__VA_ARGS__)
#else
#define db(...) 42
#endif
typedef long long ll;
typedef long double ld;
const int MOD = 998244353;
struct Mint {
	int val;
	Mint() { val = 0; }
	Mint(ll x) {
		val = (-MOD <= x && x < MOD) ? x : x % MOD;
		if (val < 0) val += MOD;
	}
	template <typename U>
	explicit operator U() const { return (U)val; }
	friend bool operator==(const Mint& a, const Mint& b) { return a.val == b.val; }
	friend bool operator!=(const Mint& a, const Mint& b) { return !(a == b); }
	friend bool operator<(const Mint& a, const Mint& b) { return a.val < b.val; }
	Mint& operator+=(const Mint& m) { if ((val += m.val) >= MOD) val -= MOD; return *this; }
	Mint& operator-=(const Mint& m) { if ((val -= m.val) < 0) val += MOD; return *this; }
	Mint& operator*=(const Mint& m) { val = (ll)val * m.val % MOD; return *this; }
	friend Mint modex(Mint a, ll p) {
		assert(p >= 0);
		Mint ans = 1;
		for (; p; p >>= 1, a *= a) if (p & 1) ans *= a;
		return ans;
	}
	Mint& operator/=(const Mint& m) { return *this *= modex(m, MOD - 2); }
	Mint& operator++() { return *this += 1; }
	Mint& operator--() { return *this -= 1; }
	Mint operator++(int) { Mint result(*this); *this += 1; return result; }
	Mint operator--(int) { Mint result(*this); *this -= 1; return result; }
	Mint operator-() const { return Mint(-val); }
	friend Mint operator+(Mint a, const Mint& b) { return a += b; }
	friend Mint operator-(Mint a, const Mint& b) { return a -= b; }
	friend Mint operator*(Mint a, const Mint& b) { return a *= b; }
	friend Mint operator/(Mint a, const Mint& b) { return a /= b; }
	friend ostream& operator<<(ostream& os, const Mint& x) { return os << x.val; }
	friend string to_string(const Mint& b) { return to_string(b.val); }
};
vector<Mint> fac(1, 1), invfac(1, 1);
Mint binom(int n, int k) {
	if (k < 0 || k > n) return 0;
	while (fac.size() <= n) {
		fac.push_back(fac.back() * fac.size());
		invfac.push_back(1 / fac.back());
	}
	return fac[n] * invfac[k] * invfac[n - k];
}
vector<int> pfac; // pfac[i] = largest prime factor of i (pfac[i <= 1] = 0)
void genPrimes(int n) {
	pfac = vector<int>(n + 1);
	for (int i = 2; i <= n; ++i) pfac[i] = i;
	for (int i = 2; i <= n; ++i)
		if (pfac[i] == i)
			for (int j = i + i; j <= n; j += i)
				pfac[j] = i;
}
/* Prime factors (with precomputing). */
vector<pair<int, int>> factorize(int x) {
	vector<pair<int, int>> factors;
	while (x > 1) {
		int p = pfac[x];
		int cnt = 0;
		while (pfac[x] == p) {
			++cnt;
			x /= p;
		}
		factors.emplace_back(p, cnt);
	}
	return factors;
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	binom(n + 20, 0);
	genPrimes(m);
	Mint ans = 0;
	for (int i = 1; i <= m; ++i) {
		auto ps = factorize(i);
		Mint prod = 1;
		for (auto& p : ps) {
			prod *= binom(n - 1 + p.second, p.second);
		}
		ans += prod;
	}
	printf("%d\n", ans.val);
}

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <vector>
#include <random>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>

//#include <atcoder/all>

#define syosu(x) fixed<<setprecision(x)
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> P;
typedef pair<double,double> pdd;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<string> vs;
typedef vector<P> vp;
typedef vector<vp> vvp;
typedef vector<pll> vpll;
typedef pair<int,P> pip;
typedef vector<pip> vip;
const int inf=1<<30;
const ll INF=1ll<<60;
const double pi=acos(-1);
const double eps=1e-8;
const ll mod=998244353;
const int dx[8]={-1,0,1,0,1,1,-1,-1},dy[8]={0,1,0,-1,1,-1,1,-1};

//using namespace atcoder;

ll Pow(ll n,ll p){
	ll r=1;
	for(;p>0;p>>=1){
		if(p&1) r=(r*n)%mod;
		n=(n*n)%mod;
	}
	return r;
}

const int M=1000005;
ll F[M];

void Init(){
	F[0]=1;
	for(int i=1;i<M;i++) F[i]=F[i-1]*i%mod;
}

ll Div(ll n,ll m){
	return n*Pow(m,mod-2)%mod;
}

ll nCk(ll n,ll k){
	return Div(F[n],F[n-k]*F[k]%mod);
}


int n,m;

int main(){
	Init();
	cin>>n>>m;
	ll res=1;
	for(int i=2;i<=m;i++){
		vi a;
		int x=i;
		for(int j=2;j*j<=x;j++) if(x%j==0){
			a.push_back(j);
			while(x%j==0) x/=j;
		}
		if(x>1) a.push_back(x);
		ll tmp=1;
		for(auto j:a){
			x=i;
			int t=0;
			while(x%j==0) x/=j,t++;
			(tmp*=nCk(n+t-1,n-1))%=mod;
		}
		(res+=tmp)%=mod;
	}
	cout<<res<<endl;
}










