#include <bits/stdc++.h>
#define clog(x) std::clog << (#x) << " is " << (x) << '\n';
using ll = long long;
// #include "include/izlyforever.hpp"
namespace NFTS {
int M = 998244353, g = 3;
std::vector<int> rev, roots{0, 1};
int powMod(int x, int n) {
int r(1);
while (n) {
if (n&1) r = 1ll * r * x % M;
n >>= 1; x = 1ll * x * x % M;
}
return r;
}
void dft(std::vector<int> &a) {
int n = a.size();
if ((int)rev.size() != n) {
int k = __builtin_ctz(n) - 1;
rev.resize(n);
for (int i = 0; i < n; ++i) {
rev[i] = rev[i >> 1] >> 1 | (i & 1) << k;
}
}
if ((int)roots.size() < n) {
int k = __builtin_ctz(roots.size());
roots.resize(n);
while ((1 << k) < n) {
int e = powMod(g, (M - 1) >> (k + 1));
for (int i = 1 << (k - 1); i < (1 << k); ++i) {
roots[2 * i] = roots[i];
roots[2 * i + 1] = 1ll * roots[i] * e % M;
}
++k;
}
}
for (int i = 0; i < n; ++i) if (rev[i] < i) {
std::swap(a[i], a[rev[i]]);
}
for (int k = 1; k < n; k *= 2) {
for (int i = 0; i < n; i += 2 * k) {
for (int j = 0; j < k; ++j) {
int u = a[i + j];
int v = 1ll * a[i + j + k] * roots[k + j] % M;
int x = u + v, y = u - v;
if (x >= M) x -= M;
if (y < 0) y += M;
a[i + j] = x;
a[i + j + k] = y;
}
}
}
}
void idft(std::vector<int> &a) {
int n = a.size();
std::reverse(a.begin() + 1, a.end());
dft(a);
int inv = powMod(n, M - 2);
for (int i = 0; i < n; ++i) {
a[i] = 1ll * a[i] * inv % M;
}
}
} //namespace NFTS
// 如果需要换模 M,那么就把 M 当做全局变量提出来,NFT 中 g, rev, root 需要重新初始化。
// 如果只需要换模几个常数 M,可使用 template<ll M>(但是不是特别推荐)
class PolyS {
void reverse() {
std::reverse(a.begin(), a.end());
}
public:
static inline const int M = NFTS::M;
static inline const int inv2 = (M + 1) / 2;
std::vector<int> a;
PolyS() {}
PolyS(int x) { if (x) a = {x};}
PolyS(const std::vector<int> _a) : a(_a) {}
int size() const { return a.size();}
int& operator[](int id) { return a[id];}
int at(int id) const {
if (id < 0 || id >= (int)a.size()) return 0;
return a[id];
}
PolyS operator-() const {
auto A = *this;
for (auto &x : A.a) x = (x == 0 ? 0 : M - x);
return A;
}
PolyS mulXn(int n) const {
auto b = a;
b.insert(b.begin(), n, 0);
return PolyS(b);
}
PolyS modXn(int n) const {
if (n > size()) return *this;
return PolyS({a.begin(), a.begin() + n});
}
PolyS divXn(int n) const {
if (size() <= n) return PolyS();
return PolyS({a.begin() + n, a.end()});
}
PolyS &operator+=(const PolyS &rhs) {
if (size() < rhs.size()) a.resize(rhs.size());
for (int i = 0; i < rhs.size(); ++i) {
if ((a[i] += rhs.a[i]) >= M) a[i] -= M;
}
return *this;
}
PolyS &operator-=(const PolyS &rhs) {
if (size() < rhs.size()) a.resize(rhs.size());
for (int i = 0; i < rhs.size(); ++i) {
if ((a[i] -= rhs.a[i]) < 0) a[i] += M;
}
return *this;
}
PolyS &operator*=(PolyS rhs) {
int n = size(), m = rhs.size(), tot = std::max(1, n + m - 1);
int sz = 1 << std::__lg(tot * 2 - 1);
a.resize(sz);
rhs.a.resize(sz);
NFTS::dft(a);
NFTS::dft(rhs.a);
for (int i = 0; i < sz; ++i) {
a[i] = 1ll * a[i] * rhs.a[i] % M;
}
NFTS::idft(a);
return *this;
}
PolyS &operator/=(PolyS rhs) {
int n = size(), m = rhs.size();
if (n < m) return (*this) = PolyS();
reverse();
rhs.reverse();
(*this) *= rhs.inv(n - m + 1);
a.resize(n - m + 1);
reverse();
return *this;
}
PolyS &operator%=(PolyS rhs) {
return (*this) -= (*this) / rhs * rhs;
}
PolyS operator+(const PolyS &rhs) const {
return PolyS(*this) += rhs;
}
PolyS operator-(const PolyS &rhs) const {
return PolyS(*this) -= rhs;
}
PolyS operator*(PolyS rhs) const {
return PolyS(*this) *= rhs;
}
PolyS operator/(PolyS rhs) const {
return PolyS(*this) /= rhs;
}
PolyS operator%(PolyS rhs) const {
return PolyS(*this) %= rhs;
}
PolyS powModPoly(int n, PolyS p) {
PolyS r(1), x(*this);
while (n) {
if (n&1) (r *= x) %= p;
n >>= 1; (x *= x) %= p;
}
return r;
}
int inner(const PolyS &rhs) {
int r = 0, n = std::min(size(), rhs.size());
for (int i = 0; i < n; ++i) {
r = (r + 1ll * a[i] * rhs.a[i]) % M;
}
return r;
}
PolyS derivation() const {
if (a.empty()) return PolyS();
int n = size();
std::vector<int> r(n - 1);
for (int i = 1; i < n; ++i) r[i - 1] = 1ll * a[i] * i % M;
return PolyS(r);
}
PolyS integral() const {
if (a.empty()) return PolyS();
int n = size();
std::vector<int> r(n + 1), inv(n + 1, 1);
for (int i = 2; i <= n; ++i) inv[i] = 1ll * (M - M / i) * inv[M % i] % M;
for (int i = 0; i < n; ++i) r[i + 1] = 1ll * a[i] * inv[i + 1] % M;
return PolyS(r);
}
PolyS inv(int n) const {
assert(a[0] != 0);
PolyS x(NFTS::powMod(a[0], M - 2));
int k = 1;
while (k < n) {
k *= 2;
x *= (PolyS(2) - modXn(k) * x).modXn(k);
}
return x.modXn(n);
}
// 需要保证首项为 1
PolyS log(int n) const {
return (derivation() * inv(n)).integral().modXn(n);
}
// 需要保证首项为 0
PolyS exp(int n) const {
PolyS x(1);
int k = 1;
while (k < n) {
k *= 2;
x = (x * (PolyS(1) - x.log(k) + modXn(k))).modXn(k);
}
return x.modXn(n);
}
// 需要保证首项为 1,开任意次方可以先 ln 再 exp 实现。
PolyS sqrt(int n) const {
PolyS x(1);
int k = 1;
while (k < n) {
k *= 2;
x += modXn(k) * x.inv(k);
x = x.modXn(k) * inv2;
}
return x.modXn(n);
}
// 减法卷积,也称转置卷积 {\rm MULT}(F(x),G(x))=\sum_{i\ge0}(\sum_{j\ge 0}f_{i+j}g_j)x^i
PolyS mulT(PolyS rhs) const {
if (rhs.size() == 0) return PolyS();
int n = rhs.size();
std::reverse(rhs.a.begin(), rhs.a.end());
return ((*this) * rhs).divXn(n - 1);
}
int eval(int x) {
int r = 0, t = 1;
for (int i = 0, n = size(); i < n; ++i) {
r = (r + 1ll * a[i] * t) % M;
t = 1ll * t * x % M;
}
return r;
}
// 多点求值新科技:https://jkloverdcoi.github.io/2020/08/04/转置原理及其应用/
std::vector<int> evals(std::vector<int> x) const {
if (size() == 0) return std::vector<int>(x.size());
int n = x.size();
std::vector<int> ans(n);
std::vector<PolyS> g(4 * n);
std::function<void(int, int, int)> build = [&](int l, int r, int p) {
if (r - l == 1) {
// g[p] = std::vector<int>{1, x[i] ? M - x[l] : 0};
g[p] = PolyS({1, x[l] ? M - x[l] : 0});
} else {
int m = (l + r) / 2;
build(l, m, 2 * p);
build(m, r, 2 * p + 1);
g[p] = g[2 * p] * g[2 * p + 1];
}
};
build(0, n, 1);
std::function<void(int, int, int, const PolyS &)> solve = [&](int l, int r, int p, const PolyS &f) {
if (r - l == 1) {
ans[l] = f.at(0);
} else {
int m = (l + r) / 2;
solve(l, m, 2 * p, f.mulT(g[2 * p + 1]).modXn(m - l));
solve(m, r, 2 * p + 1, f.mulT(g[2 * p]).modXn(r - m));
}
};
solve(0, n, 1, mulT(g[1].inv(size())).modXn(n));
return ans;
}
}; // PolyS 全家桶测试:https://www.luogu.com.cn/training/3015#information
std::vector<int> g, f;
//分治NTT
void CDQ(int l, int r)
{
if (l >= r)
return;
int mid = l + r >> 1;
CDQ(l, mid);
std::vector<int> tmp(mid - l + 1), tmp2(r - l + 1);
for (int i = 0; i <= r - l; i++)
tmp2[i] = g[i];
for (int i = l; i <= mid; i++)
tmp[i-l] = f[i];
PolyS A(tmp), B(tmp2);
A *= B;
for (int i = mid + 1; i <= r; i++)
f[i] = (f[i] + A.a[i-l]) % NFTS::M;
CDQ(mid + 1, r);
}
int main() {
int n;
scanf("%d", &n);
g.resize(n), f.resize(n);
g[0] = 0;
f[0] = 1;
for (int i = 1; i < n; i++)
scanf("%d", &g[i]);
CDQ(0, n - 1);
for (int i = 0; i < n; i++)
printf("%d ", f[i]);
puts("");
return 0;
}