#include <bits/stdc++.h>
using namespace std;
#define fast_io cin.tie(0);ios_base::sync_with_stdio(0);
string to_string(string s) { return '"' + s + '"';}
string to_string(char s) { return string(1, s);}
string to_string(const char* s) { return to_string((string) s);}
string to_string(bool b) { return (b ? "true" : "false");}
template <typename A> string to_string(A);
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) {bool f = 1; string r = "{"; for (const auto &x : v) {if (!f)r += ", "; f = 0; r += to_string(x);} return r + "}";}
void debug_out() { cout << endl; }
void show() { cout << endl; }
void pret() { cout << endl; exit(0);}
template <typename Head, typename... Tail> void debug_out(Head H, Tail... T) {cout << " " << to_string(H); debug_out(T...);}
template <typename Head, typename... Tail> void show(Head H, Tail... T) {cout <<H<<" "; show(T...);}
template <typename Head, typename... Tail> void pret(Head H, Tail... T) {cout <<H<<" "; pret(T...);}
#define pr(...) cout << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
typedef long long ll;
// #define int ll
typedef long double ld;
typedef vector<int> vi;
#define disp(x) cout<<x<<" ";
#define rep(i,a,b) for(int i=a;i<(int)b;i++)
#define fo(i,a,b) for(int i=a;i<=(int)b;i++)
#define rf(i,a,b) for(int i=a;i>=(int)b;i--)
#define mp make_pair
#define pb emplace_back
#define F first
#define S second
#define endl '\n'
//cout.setf(ios::fixed);cout.precision(18)
const int MOD = 998244353;
const int maxn = 2e5+10;

ll factorial[maxn], inverse[maxn];

ll power(ll a, ll b){                       
    ll x = 1, y = a;
    while (b > 0){
        if (b%2){
            x = (x*y)%MOD;
        }
        y = (y*y)%MOD;
        b /= 2;
    }
    return x%MOD;
}   
 
ll modular_inverse(ll n){              
    return power(n, MOD-2);
}
 
ll nCr(ll n, ll k){
	if(n < k) return 0;
    ll flag= ((factorial[n])*(modular_inverse(factorial[k])))%MOD;
    return (flag*modular_inverse(factorial[n-k]))%MOD;
}

void add(int &a, int b){
	a += b;
	if(a >= MOD) a -= MOD;
	if(a < 0) a += MOD;
}

const int lognum = 19;

int dp[maxn][lognum];

int f(){
	int n, m;
	cin >> n >> m;
	fo(i, 1, m) dp[i][1] = 1;
	int ans = m;
	fo(j, 2, lognum - 1){
		if(j > n) break;
		// vector < bool > visited(m + 1, 0);
		int curr = 0;
		fo(i, 1, m){
			if(dp[i][j - 1] == 0) continue;
			for(int k = i + i; k <= m; k += i){
				add(dp[k][j], dp[i][j - 1]);
			}
		}
		fo(i, 2, m){
			add(curr, dp[i][j]);
		}
		// show(j, curr, nCr(n - 1, j - 1));
		add(ans, (ll(curr) * nCr(n - 1, j - 1)) % MOD);
	}
	return ans;
}

int32_t main(){
    fast_io;
    int t = 1;
    factorial[0] = 1;
    // inverse[0] = 1;
    fo(i, 1, maxn - 1){
    	factorial[i] = (factorial[i - 1] * i) % MOD;
    	// inverse[i] = modular_inverse(factorial[i]);
    }
    // cin>>t;
    while(t--){
    	show(f());

    	// f();

    	// if(f()){
    	// 	cout<<"YES"<<endl;
    	// }
    	// else cout<<"NO"<<endl;
    }
    return 0;
}
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#ifdef ENABLE_DEBUG
#define dump(a) cerr<<#a<<"="<<a<<endl
#define dumparr(a,n) cerr<<#a<<"["<<n<<"]="<<a[n]<<endl
#else
#define dump(a) 
#define dumparr(a,n) 
#endif
#define FOR(i, a, b) for(ll i = (ll)a;i < (ll)b;i++)
#define For(i, a) FOR(i, 0, a)
#define REV(i, a, b) for(ll i = (ll)b-1LL;i >= (ll)a;i--)
#define Rev(i, a) REV(i, 0, a)
#define REP(a) For(i, a)
#define SIGN(a) (a==0?0:(a>0?1:-1))

typedef long long int ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<ll, ll> pll;
typedef pair<ll,pll> ppll;
typedef vector<ll> vll;
typedef long double ld;
typedef pair<ld,ld> pdd;

pll operator+(pll a,pll b){
  return pll(a.first+b.first,a.second+b.second);
}
pll operator-(pll a,pll b){
  return pll(a.first-b.first,a.second-b.second);
}
pll operator*(ll a,pll b){
  return pll(b.first*a,b.second*a);
}
const ll INF=(1LL<<60);
#if __cplusplus<201700L
ll gcd(ll a, ll b) {
  a=abs(a);
  b=abs(b);
  if(a==0)return b;
  if(b==0)return a;
  if(a < b) return gcd(b, a);
  ll r;
  while ((r=a%b)) {
    a = b;
    b = r;
  }
  return b;
}
#endif
template<class T>
bool chmax(T& a,const T& b){
  if(a<b){
    a=b;
    return true;
  }
  return false;
}
template<class T>
bool chmin(T& a,const T& b){
  if(a>b){
    a=b;
    return true;
  }
  return false;
}
template<class S,class T>
std::ostream& operator<<(std::ostream& os,pair<S,T> a){
  os << "(" << a.first << "," << a.second << ")";
  return os;
}
template<class T>
std::ostream& operator<<(std::ostream& os,vector<T> a){
  os << "[ ";
  REP(a.size()){
    os<< a[i] << " ";
  }
  os<< " ]";
  return os;
}

const long long MOD = 998244353;
const long long max_cache=1000000;
long long cache_fact[max_cache],cache_inv_fact[max_cache];
long long combination_cached(long long n,long long r){
  ll m=MOD;
  static bool cached=false;
  if(cached==false){
    cached=true;
    cache_inv_fact[1]=1;
    for (long long i = 2; i < max_cache; i++) {
      cache_inv_fact[i]=(m-m/i)*cache_inv_fact[m%i]%m;
    }
    for (long long i = 2; i < max_cache; i++){
      cache_inv_fact[i]=cache_inv_fact[i]*cache_inv_fact[i-1]%m;
    }
    cache_fact[0]=1;
    for (long long i = 1; i < max_cache; i++) {
      cache_fact[i]=cache_fact[i-1]*i%m;
    }
  }
  if(r<0||r>n)return 0;
  if(r==0||r==n)return 1;
  if(n>m){
    std::cerr<<"Combination Error: n is greater than m"<<std::endl;
    exit(1);
  }
  r=min(r,n-r);
  return cache_fact[n]*cache_inv_fact[r]%m*cache_inv_fact[n-r]%m;
}
long long homogeneous(long long n,long long r){
  return combination_cached(n+r-1,r);
}
void solve(long long N, long long M){
  if(N==1){
    cout<<M<<endl;
    return;
  }
  vector<ll> primes{2};
  for (ll i = 3; i*i <= M; i+=2)
  {
    bool f=true;
    for (auto &&j : primes)
    {
      if(i%j==0){
        f=false;
        break;
      }
    }
    if(f){
      primes.push_back(i);
    }
  }
  ll ans=0;
  FOR(i,1,M+1){
    ll cur=i;
    vector<ll> cnts;
    for (auto &&p : primes)
    {
      ll cnt=0;
      while(cur%p==0){
        ++cnt;
        cur/=p;
      }
      if(cnt>0){
        cnts.push_back(cnt);
      }
    }
    if(cur>1){
      cnts.push_back(1);
    }
    ll curans=1;
    for (auto &&j : cnts)
    {
      curans*=homogeneous(N,j);
      curans%=MOD;
    }
    dump(i);
    dump(curans);
    ans=(ans+curans)%MOD;
  }
  cout<<ans<<endl;
  return;
}

int main(){
  cout<<setprecision(1000);
  long long N;
    scanf("%lld",&N);
    long long M;
    scanf("%lld",&M);
  solve(N, M);
  return 0;
}
