#include using namespace std; static const long long MOD = 998244353; long long mod_pow(long long a, long long e) { long long r = 1 % MOD; a %= MOD; while (e > 0) { if (e & 1) r = (r * a) % MOD; a = (a * a) % MOD; e >>= 1; } return r; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, M; cin >> N >> M; // inv[1..N] を O(N) で前計算 vector inv(N + 1, 0); inv[1] = 1; for (int i = 2; i <= N; i++) { inv[i] = MOD - (MOD / i) * inv[MOD % i] % MOD; } // 二項係数用(n は最大 M 程度) vector fact(M + 1), invfact(M + 1); fact[0] = 1; for (int i = 1; i <= M; i++) fact[i] = fact[i - 1] * i % MOD; invfact[M] = mod_pow(fact[M], MOD - 2); for (int i = M; i >= 1; i--) invfact[i - 1] = invfact[i] * i % MOD; auto C = [&](int n, int r) -> long long { if (r < 0 || r > n) return 0; return fact[n] * invfact[r] % MOD * invfact[n - r] % MOD; }; // 閾値(経験的にこの程度で十分) int S = min(N, 450); vector D(M + 1, 0); for (int k = 1; k <= N; k++) { if (k > M) { // 1回目に引いた S は M 回以内に復帰しない cout << 1 << "\n"; continue; } int B = N - k + 1; // 定常時の箱サイズ if (B == 1) { // 箱に1個しかない:復帰したら必ず引かれるので、周期 k で確定 long long ans = 1 + (M - 1) / k; ans %= MOD; cout << ans << "\n"; continue; } if (k <= S) { // 小さい k:時間 DP(窓和) long long invB = inv[B]; D[1] = 1; for (int t = 2; t <= k; t++) D[t] = 0; long long ans = 1; if (k == 1) { // 以降は毎手独立に 1/N ans = (1 + (long long)(M - 1) * invB) % MOD; cout << ans << "\n"; continue; } long long W = 0; // W = sum_{j=1}^{k-1} D[t-j] を逐次管理 for (int t = k + 1; t <= M; t++) { long long dt = (1 - W) % MOD; if (dt < 0) dt += MOD; dt = dt * invB % MOD; D[t] = dt; ans += dt; ans %= MOD; // W_{t+1} = W_t + D[t] - D[t-k+1] W += dt; if (W >= MOD) W -= MOD; W -= D[t - k + 1]; if (W < 0) W += MOD; } cout << ans % MOD << "\n"; } else { // 大きい k:二項分布の裾確率(m は小さい) long long p = inv[B]; long long q = (long long)(B - 1) * inv[B] % MOD; // 1 - p long long r = inv[B - 1]; // p/q = 1/(B-1) int mmax = (M - 1) / k; long long ans = 1; // m=1 のとき n = M-1 - (k-1) = M-k, よって q^n int n1 = M - k; long long qpow = mod_pow(q, n1); // 次の m では n が (k-1) 減るので、q^{-(k-1)} を掛けて更新 // inv(q) = B/(B-1) long long invq = (long long)B * inv[B - 1] % MOD; long long step = mod_pow(invq, k - 1); // q^{-(k-1)} for (int m = 1; m <= mmax; m++) { int n = M - 1 - m * (k - 1); if (n < m) break; // Bin(n,p) >= m は不可能 // sum_{j=0}^{m-1} C(n,j) p^j q^{n-j} // = q^n * sum_{j=0}^{m-1} C(n,j) (p/q)^j long long sum = 0; long long rpow = 1; for (int j = 0; j <= m - 1; j++) { long long term = C(n, j) * rpow % MOD; sum += term; if (sum >= MOD) sum -= MOD; rpow = rpow * r % MOD; } sum = sum * qpow % MOD; long long prob = (1 - sum) % MOD; if (prob < 0) prob += MOD; ans += prob; if (ans >= MOD) ans -= MOD; // 次の m 用に q^n を更新(n が (k-1) 減る) qpow = qpow * step % MOD; } cout << ans % MOD << "\n"; } } return 0; }