#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <random>
#include <complex>
#include <assert.h>

#include <atcoder/dsu.hpp>
#include <atcoder/fenwicktree.hpp>
#include <atcoder/segtree.hpp>
#include <atcoder/lazysegtree.hpp>
#include <atcoder/maxflow.hpp>
#include <atcoder/mincostflow.hpp>
#include <atcoder/modint.hpp>
#include <atcoder/convolution.hpp>

using namespace std;
using namespace atcoder;

////////////////	型名など
typedef long long ll;
#define endl '\n'

////////////////	各種定数
const ll INF = 1LL << 60;
const double EPS = 1e-12;

////////////////	便利なテンプレート関数
template<typename T>
inline bool chmin(T& x, T a) {
	if (x >= a) { x = a; return true; }
	return false;
}

template<typename T>
inline bool chmax(T& x, T a) {
	if (x <= a) { x = a; return true; }
	return false;
}

/////////////         modの計算

static const ll MOD = 998244353LL;
static const bool MOD_IS_PRIME = internal::is_prime<MOD>;

struct mint : static_modint<MOD> {
	mint() : static_modint() {}
	mint(const static_modint<MOD>& other) : static_modint(other.val()) {}
	template <class T, internal::is_signed_int_t<T> * = nullptr>mint(T v) : static_modint(v) {}
	template <class T, internal::is_unsigned_int_t<T> * = nullptr>mint(T v) : static_modint(v) {}
	
	inline operator ll() const { return val(); }
	friend ostream& operator<<(ostream& output, const mint& x) {
		output << x.val();
		return output;
	}
	friend istream& operator>>(istream& input, mint& x){
		ll buf; input >> buf; x = buf;
		return input;
	}

	template<typename T>friend mint operator+(const mint& lhs, const T rhs) { return mint(lhs) += rhs; }
	template<typename T>friend mint operator+(const T lhs, const mint& rhs) { return mint(lhs) += rhs; }
	friend mint operator+(const mint& lhs, const mint& rhs) { return mint(lhs) += rhs; }
	template<typename T>friend mint operator-(const mint& lhs, const T rhs) { return mint(lhs) -= rhs; }
	template<typename T>friend mint operator-(const T lhs, const mint& rhs) { return mint(lhs) -= rhs; }
	friend mint operator-(const mint& lhs, const mint& rhs) { return mint(lhs) -= rhs; }
	template<typename T>friend mint operator*(const mint& lhs, const T rhs) { return mint(lhs) *= rhs; }
	template<typename T>friend mint operator*(const T lhs, const mint& rhs) { return mint(lhs) *= rhs; }
	friend mint operator*(const mint& lhs, const mint& rhs) { return mint(lhs) *= rhs; }
	template<typename T>friend mint operator/(const mint& lhs, const T rhs) { return mint(lhs) /= rhs; }
	template<typename T>friend mint operator/(const T lhs, const mint& rhs) { return mint(lhs) /= rhs; }
	friend mint operator/(const mint& lhs, const mint& rhs) { return mint(lhs) /= rhs; }
	template<typename T>friend bool operator==(const mint& lhs, const T rhs) { return lhs.val() == mint(rhs).val(); }
	template<typename T>friend bool operator==(const T lhs, const mint& rhs) { return mint(lhs).val() == rhs.val(); }
	friend bool operator==(const mint& lhs, const mint& rhs) { return lhs.val() == rhs.val(); }
	template<typename T>friend bool operator!=(const mint& lhs, const T rhs) { return lhs.val() != mint(rhs).val(); }
	template<typename T>friend bool operator!=(const T lhs, const mint& rhs) { return mint(lhs).val() != rhs.val(); }
	friend bool operator!=(const mint& lhs, const mint& rhs) { return lhs.val() != rhs.val(); }

	mint pow(ll n) const {
		if (!MOD_IS_PRIME) {
			if (n < 0) {
				return inv().pow(-n);
			}
			return raw(val()).pow(n);
		}
		if (n < 0) {
			n += ((abs(n) + MOD - 2) / (MOD - 1)) * (MOD - 1);
		}
		else if (n >= MOD - 1) { n %= MOD - 1; }
		return raw(val()).pow(n);
	}
	mint inv() const;
};

inline mint mod_inv(mint a) {
	const ll inv_max = 300000;
	static vector<ll> inv;

	assert(a != 0);

	if (inv.size() == 0) {
		inv.resize(inv_max);
		for (int i = 0; i < inv_max; i++) {
			if (i <= 1) { inv[i] = i; }
			else { inv[i] = ((MOD - MOD / i) * inv[MOD % i]) % MOD; }
		}
	}
	ll p = MOD, q = a, r;
	mint m = 0, n = 1, c;
	while (1) {
		if (q < inv_max) { return n * inv[q]; }
		c = p / q; r = p % q; c = m - n * c;
		p = q, q = r; m = n, n = c;
	}
}

mint mint::inv() const { return mod_inv(*this); }

inline ll mod_log(mint a, mint x) {
	ll A = sqrt(MOD);
	ll B = (MOD + A - 1) / A;
	map<ll, ll> mp1, mp2;
	ll p0 = a.val();
	ll q0 = a.pow(-A).val();
	ll p = 1;
	ll q = x.val();
	for (int i = 0; i < A; i++) {
		mp1.insert({ p, i });
		p = (p * p0) % MOD;
	}
	for (int i = 0; i < B; i++) {
		mp2.insert({ q, A * i });
		q = (q * q0) % MOD;
	}
	auto itr1 = mp1.begin();
	auto itr2 = mp2.begin();
	while (itr1 != mp1.end() && itr2 != mp2.end()) {
		if (itr1->first < itr2->first) {
			itr1++;
		}
		else if (itr1->first == itr2->first) {
			return itr1->second + itr2->second;
		}
		else {
			itr2++;
		}
	}
	return 0;
}

inline mint mod_factorial(mint n, bool inverse = false) {
	static vector<mint> factorial, factorial_inv;

	ll M = factorial.size();
	if (M <= n) {
		if (M == 0) { factorial.push_back(1); factorial_inv.push_back(1); M++; }
		if (M == 1) { factorial.push_back(1); factorial_inv.push_back(1); M++; }

		for (mint i = M; i <= n; i++) {
			factorial.push_back(factorial.back() * i);
			factorial_inv.push_back(factorial_inv.back() / i);
		}
	}
	if (inverse == true) { return factorial_inv[n]; }
	else { return factorial[n]; }
}
inline mint mod_combination(mint n, mint r) {
	assert(r <= n);
	return mod_factorial(n) * mod_factorial(n - r, true) * mod_factorial(r, true);
}

int main() {
	ios::sync_with_stdio(false);
	std::cin.tie(0);

	int N, M; cin >> N >> M;

	vector<mint> A(N);
	vector<mint> B(M);

	for (int i = 0; i < N; i++) { cin >> A[i]; }
	for (int i = 0; i < M; i++) { cin >> B[i]; }

	auto C = convolution(A, B);
	for (int i = 0; i < C.size(); i++) {
		cout << C[i] << " ";
	}

	return 0;
}

Measured memory_bytes: 21328