#include <climits>
#include <iostream>
#include <unordered_map>
#include <map>
#include <vector>
#include <unordered_set>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#include <cmath>
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#include <iostream>
#include <unordered_map>
#include <map>
#include <vector>
#include <unordered_set>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#include <cmath>
#define MAXN  10000000
using namespace std;

long long mod=998244353;
int spf[MAXN]; 
void sieve() 
{ 
    spf[1] = 1; 
    for (int i=2; i<MAXN; i++) 
  
        // marking smallest prime factor for every 
        // number to be itself. 
        spf[i] = i; 
  
    // separately marking spf for every even 
    // number as 2 
    for (int i=4; i<MAXN; i+=2) 
        spf[i] = 2; 
  
    for (int i=3; i*i<MAXN; i++) 
    { 
        // checking if i is prime 
        if (spf[i] == i) 
        { 
            // marking SPF for all numbers divisible by i 
            for (int j=i*i; j<MAXN; j+=i) 
  
                // marking spf[j] if it is not  
                // previously marked 
                if (spf[j]==j) 
                    spf[j] = i; 
        } 
    } 
} 
  
// A O(log n) function returning primefactorization 
// by dividing by smallest prime factor at every step 
unordered_map<int, int> getFactorization(int x) 
{ 
    unordered_map<int, int> factors;
    while (x != 1) 
    { 
        factors[spf[x]]++;
        x = x / spf[x]; 
    } 
    return factors;
} 

int main(){
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int tt=1;
    sieve();
    long long dp[21][200001];
    for(int i=20;i>=1;i--){
        for(int j=200000;j>=0;j--){
            if(i==20 && j==200000){
                dp[i][j]=1;
                continue;
            }
            if(j==200000){
                dp[i][j]=dp[i+1][j];
                continue;
            }
            if(i==20){
                dp[i][j]=(1+dp[i][j+1])%mod;
                continue;
            }
            dp[i][j]=(dp[i][j+1]+dp[i+1][j])%mod;
        }
    }
    while(tt--){
        int n, m;
        cin>>n>>m;
        long long ways=1;
        for(int i=2;i<=m;i++){
            unordered_map<int, int> factors=getFactorization(i);
            long curr=1;
            for(auto it=factors.begin();it!=factors.end();it++){

                curr=(curr*dp[21-(it->second)][200001-n])%mod;
            }
            ways=(ways+curr)%mod;
        }
        cout<<ways<<endl;

    }


}


//3 4 2 1 5 6

//1 2 3

#include <bits/stdc++.h>

#define endl '\n'
using namespace std;
using ll = long long;
const int MOD = 998244353;
static const int MX = 200100;

ll poww(ll a, ll b) {
	if (b == 0) {
		return 1;
	}
	if (b & 1) {
		return (a * poww(a, b - 1)) % MOD;
	}
	return poww((a * a) % MOD, b >> 1);
}

ll inv(ll a) {
	return poww(a, MOD - 2);
}

ll fact[MX + 1];
ll invfact[MX + 1];

ll C(int n, int k) {
	return ((fact[n] * invfact[k]) % MOD * invfact[n - k]) % MOD;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	fact[0] = 1;
	invfact[0] = 1;
	for (int i = 1; i <= MX; ++i) {
		fact[i] = (fact[i - 1] * i) % MOD;
		// there was linear time formula, but who cares
		invfact[i] = inv(fact[i]);
	}
    static vector<int> sieve(MX + 1);
    iota(sieve.begin(), sieve.end(), 0);
    for (int i = 2; i * i <= MX; ++i) {
        if (sieve[i] < i) continue;
        for (int j = i * i; j <= MX; j += i) {
            sieve[j] = i;
        }
    }
	int n, m;
	cin >> n >> m;
	ll gans = 0;
	for (int i = 1; i <= m; ++i) {
		ll ans = 1;
		int x = i;
	    for (int cur = sieve[x]; x > 1; cur = sieve[x]) {
	        int cnt = 0;
	        for (; x % cur == 0; cnt++, x /= cur);
	        ans *= C(n + cnt - 1, cnt);
	    	ans %= MOD;
	    }
	    gans += ans;
	    if (gans >= MOD) {
	    	gans -= MOD;
	    }
	}
	cout << gans << endl;
}
