#include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define chmax(a, b) a = max(a, b);
#define chmin(a, b) a = min(a, b);
using namespace std;
using ll = long long;
using P = pair<int,int>;

#define MOD 998244353
struct mint {
	int i;
	mint() : i(0) {}
	mint(int x) {
		i = int(x % MOD);
		if (i < 0) i += MOD;
	}
	template<class T> mint(T x) {
		i = int(x % MOD);
		if (i < 0) i += MOD;
	}
	mint operator+(const mint x) const {return i + x.i;}
	mint operator-(const mint x) const {return i - x.i;}
	mint operator*(const mint x) const {return (long long)i * x.i;}
	mint operator/(const mint x) const {return (long long)i * x.pow(MOD - 2).i;}
	mint inv() {return pow(MOD - 2);}
	template<class T> mint pow(T p) const {
		long long r = 1;
		long long t = i;
		for(; p > 0; p >>= 1) {
			if (p & 1) r = r * t % MOD;
			t = t * t % MOD;
		}
		return r;
	}
	template<class T1, class T2> static mint pow(T1 a, T2 b) {
		long long r = 1;
		long long t = (long long)(a % MOD);
		for(; b > 0; b >>= 1) {
			if (b & 1) r = r * t % MOD;
			t = t * t % MOD;
		}
		return r;
	}
	mint& operator+=(const mint x) {
		i = (i + x.i) % MOD;
		return *this;
	}
	mint& operator-=(const mint x) {
		i = i - x.i;
		if (i < 0) i += MOD;
		return *this;
	}
	mint& operator*=(const mint x) {
		i = (int)((long long)i * x.i % MOD);
		return *this;
	}
	mint& operator/=(const mint x) {
		i = (long long)i * x.pow(MOD - 2).i % MOD;
		return *this;
	}
};

std::ostream& operator<<(std::ostream& os, const mint& m) {
	return os << m.i;
}
struct combination {
  vector<mint> fact, ifact;
  combination(int n):fact(n+1),ifact(n+1) {
    assert(n < MOD);
    fact[0] = 1;
    for (int i = 1; i <= n; ++i) fact[i] = fact[i-1]*i;
    ifact[n] = fact[n].inv();
    for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i]*i;
  }
  mint operator()(int n, int k) {
    if (k == 0) return 1;
    if (k < 0 || k > n) return 0;
    return fact[n]*ifact[k]*ifact[n-k];
  }
} comb(5000);

template<class T>
struct SegTree_A {
	std::vector<T> d;
	int sz;
	int base;
	const T e;
	T merge(const T& i, const T& j){return i+j;}
	SegTree_A(int size): sz(size), e() {
		int k = 1;
		while(sz > k) k <<= 1;
		d = std::vector<T>(2 * k - 1, e);
		base = k - 1;
	}
	void update_upper(int i) {
		while(i > 0) {
			i = (i-1)/2;
			d[i] = merge(d[i*2+1], d[i*2+2]);
		}
	}
	void add(int i, T x) {
		assert(0 <= i && i < sz);
		int t = base + i;
		d[t] = d[t] + x;
		update_upper(t);
	}
	void assign(int i, T x) {
		assert(0 <= i && i < sz);
		int t = base + i;
		d[t] = x;
		update_upper(t);
	}
	T sum(int a, int b) {
		assert(0 <= a && a <= b && b <= sz);
		// sum up data in [a, b)
		return sum_sub(a, b, 0, 0, base+1);
	}
	T sum(int b) {return sum(0, b);}
	T sum_sub(int a, int b, int k, int l, int r) {
		if (b <= l || r <= a) return e;
		if (a <= l && r <= b) return d[k];
		int c = (l + r) / 2;
		return merge(
			sum_sub(a, b, 2*k+1, l, c),
			sum_sub(a, b, 2*k+2, c, r)
		);
	}
	T get(int i) {return d[base+i];}
};

int main() {
	int k, n;
	cin >> k >> n;
	vector<SegTree_A<mint>> dp(k+1, SegTree_A<mint>(n+1));
	dp[0].assign(0, 1);
	for(int i = 1; i <= k; i++) {
		rep(j, n+1) {
			dp[i].add(j, dp[i-1].get(j) + dp[i-1].sum(j) * 2);
		}
	}
	for(int i = 2; i <= 2 * k; i++) {
		int cnt = 0;
		for(int s = 1, t = i - 1; s < t; s++, t--) if (t <= k) cnt += 1;
		mint ans = 0;
		if (i&1) rep(j, n+1) {
			ans += dp[cnt].get(j) * comb(k-cnt*2-1+n-j, n-j);
		} else {
			rep(j, n+1) {
				ans += dp[cnt].get(j) 
					* comb(k-cnt*2-1-1+n-j, n-j);
			}
			rep(j, n) {
				ans += dp[cnt].get(j) 
					* comb(k-cnt*2-1-1+n-j-1, n-j-1);
			}
		}
		cout << ans << endl;
	}
}


Measured memory_bytes: 35424