#include #include #include #include #include namespace nachia{ std::pair, std::vector> CountingPrimesTable(long long maxval) { using i64 = long long; i64 n = maxval; if(n <= 1) return { {0,0}, {0,0} }; i64 sqrtn = 0; while(sqrtn * sqrtn <= n) sqrtn++; sqrtn--; std::vector prefix_sum_fairy(sqrtn+1, 0); for(i64 i=1; i<=sqrtn; i++) prefix_sum_fairy[i] = i-1; std::vector prefix_sum_devil(sqrtn+1, 0); for(i64 i=1; i<=sqrtn; i++) prefix_sum_devil[i] = n/i-1; for(i64 p=2; p<=sqrtn; p++){ i64 prime_count_p = prefix_sum_fairy[p]; i64 prime_count_p_minus1 = prefix_sum_fairy[p-1]; if(prime_count_p == prime_count_p_minus1) continue; for(i64 devil_id = 1; devil_id <= sqrtn; devil_id++){ if(devil_id * p <= sqrtn){ prefix_sum_devil[devil_id] -= prefix_sum_devil[devil_id * p] - prime_count_p_minus1; } else{ i64 tg_fairy = n / (devil_id * p); if(tg_fairy < p) break; prefix_sum_devil[devil_id] -= prefix_sum_fairy[tg_fairy] - prime_count_p_minus1; } } for(i64 fairy_id = sqrtn/p; fairy_id >= p; fairy_id--){ i64 dc = prefix_sum_fairy[fairy_id] - prime_count_p_minus1; i64 max_tg = std::min(fairy_id * p + p - 1, sqrtn); for(i64 tg_fairy = fairy_id * p; tg_fairy <= max_tg; tg_fairy++) prefix_sum_fairy[tg_fairy] -= dc; } } return std::make_pair(std::move(prefix_sum_fairy), std::move(prefix_sum_devil)); } long long CountingPrimes(long long maxval){ return CountingPrimesTable(maxval).second[1]; } } // namespace nachia namespace nachia { template std::pair, std::vector> MultiplicativePrefixSum(long long N, F1 f1, F2 f2){ using i64 = long long; if(N == 1){ std::vector f(2, Elem(0)); std::vector d(2, Elem(0)); f[1] = d[1] = Elem(1); return std::make_pair(f, d); } i64 Nr2 = 0; while((Nr2+1) * (Nr2+1) <= N) Nr2++; i64 Nr3 = 0; while((Nr3+1) * (Nr3+1) * (Nr3+1) <= N) Nr3++; i64 Nr6 = 0; while((Nr6+1) * (Nr6+1) <= Nr3) Nr6++; i64 N2r3 = std::max(Nr2, N / (N / Nr6 / Nr2 + 1)); i64 Dsz = N / (Nr2+1); i64 Asz = (Nr2+1) + Dsz; std::vector A(Asz + 1, Elem(0)); auto Aat = [Asz,Nr2,N](i64 x) -> i64 { return x <= Nr2 ? x : (Asz-N/x); }; std::vector sieve(Nr2+1, 1); sieve[0] = sieve[1] = 0; std::vector primes; for(i64 p=2; p<=Nr2; p++) if(sieve[p]){ primes.push_back(p); for(i64 q=p*p; q<=Nr2; q+=p) sieve[q] = 0; } i64 Nr2Pi = i64(primes.size()); i64 Nr3Pi = 0; while(Nr3Pi < Nr2Pi && primes[Nr3Pi] <= Nr3) Nr3Pi++; // 1 A[1] += Elem(1); // p for(i64 p : primes) if(Nr3 < p) A[p] = f1(p, 1, p); for(i64 i=1; i<=Dsz; i++) A[Asz-i] = f2(N/i); for(i64 i=1; i=1; i--){ Elem pnx = f2(N/(i*p)); A[Asz-i] += (pnx - ppre) * fp; ppre = pnx; } } for(i64 i=1; i+1 std::pair, std::vector> { std::vector fpebuf; std::vector pe; for(i64 pp=p, e=1; pp<=N; pp*=p, e++){ fpebuf.push_back(f1(p, e, pp)); pe.push_back(pp); } pe.push_back(N+1); return std::make_pair(std::move(pe), std::move(fpebuf)); }; std::vector, std::vector>> fpebufall(Nr2Pi); for(i64 px=0; px void { while(i < fwtSz){ A[i] += v; i += i & -i; } }; auto fwSum = [&](i64 r) -> Elem { Elem x = Elem(0); while(r > 0){ x += A[r]; r -= r & -r; } return x; }; for(i64 i=fwtSz-2; i>=1; i--) A[i+1] -= A[i]; for(i64 i=1; i Elem { return v < fwtSz ? fwSum(v) : A[v]; }; for( ; px>=0 && primes[px]>Nr6; px--){ auto& [xpe, xfpe] = fpebufall[px]; // N2r3 <= n for(i64 x=1; Asz-x>=fwtSz; x++){ i64 n = N / x; for(i64 e=0; xpe[e]<=n; e++){ A[Asz-x] += xfpe[e] * getAsum(Aat(n/xpe[e])); } } // search v <= N2r3 && primes[px] == lpf(v) std::vector> bfs; for(i64 e=0; xpe[e] <= N2r3; e++){ fwAdd(Aat(xpe[e]), xfpe[e]); bfs.push_back({ xpe[e], xfpe[e] }); } for(i64 pxv=px+1; pxv=1; i--) if(i+(i&-i) < fwtSz) A[i+(i&-i)] -= A[i]; for(i64 i=1; i=0; px--){ auto [pe, fpebuf] = std::move(fpebufall[px]); for(i64 i=1; i<=Dsz; i++){ for(i64 t=0; i*pe[t]<=N; t++){ A[Asz-i] += A[Aat(N/(i*pe[t]))] * fpebuf[t]; } } for(i64 i=Nr2; i>=pe[0]; i--){ for(i64 t=0; pe[t]<=i; t++){ A[i] += A[i/pe[t]] * fpebuf[t]; } } } return std::make_pair( std::vector(A.begin(), A.begin() + Nr2), std::vector(A.rbegin(), A.rbegin() + (Dsz + 1)) ); } } // namespace nachia #include using Modint = atcoder::static_modint<998244353>; using namespace std; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); using i64 = long long; i64 N; cin >> N; i64 M; cin >> M; vector X(100); for(i64 i=1; i<100; i++) X[i] = Modint(i+1).pow(N); auto [pcf, pcd] = nachia::CountingPrimesTable(M); i64 s = i64(pcf.size() - 1); auto [ansf, ansd] = nachia::MultiplicativePrefixSum( M, [&](i64 p, i64 e, i64 pe){ return X[e]; }, [&](i64 x){ return Modint((x <= s ? pcf[x] : pcd[M/x]) * X[1]); }); Modint ans = M < ansf.size() ? ansf[M] : ansd[1]; cout << ans.val() << '\n'; return 0; }