//#pragma GCC optimize("Ofast") //#pragma GCC target("avx") //#undef LOCAL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using uint = unsigned int; using ll = long long; using ull = unsigned long long; constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n - 1); } template using V = vector; template using VV = V>; struct Scanner { FILE* fp = nullptr; char line[(1 << 15) + 1]; size_t st = 0, ed = 0; void reread() { memmove(line, line + st, ed - st); ed -= st; st = 0; ed += fread(line + ed, 1, (1 << 15) - ed, fp); line[ed] = '\0'; } bool succ() { while (true) { if (st == ed) { reread(); if (st == ed) return false; } while (st != ed && isspace(line[st])) st++; if (st != ed) break; } if (ed - st <= 50) reread(); return true; } template ::value, int> = 0> bool read_single(T& ref) { if (!succ()) return false; while (true) { size_t sz = 0; while (st + sz < ed && !isspace(line[st + sz])) sz++; ref.append(line + st, sz); st += sz; if (!sz || st != ed) break; reread(); } return true; } template ::value, int> = 0> bool read_single(T& ref) { if (!succ()) return false; bool neg = false; if (line[st] == '-') { neg = true; st++; } ref = T(0); while (isdigit(line[st])) { ref = 10 * ref + (line[st++] - '0'); } if (neg) ref = -ref; return true; } template bool read_single(V& ref) { for (auto& d : ref) { if (!read_single(d)) return false; } return true; } void read() {} template void read(H& h, T&... t) { bool f = read_single(h); assert(f); read(t...); } Scanner(FILE* _fp) : fp(_fp) {} }; struct Printer { public: template void write() {} template void write(const H& h, const T&... t) { if (F) write_single(' '); write_single(h); write(t...); } template void writeln(const T&... t) { write(t...); write_single('\n'); } Printer(FILE* _fp) : fp(_fp) {} ~Printer() { flush(); } private: static constexpr size_t SIZE = 1 << 15; FILE* fp; char line[SIZE], small[50]; size_t pos = 0; void flush() { fwrite(line, 1, pos, fp); pos = 0; } void write_single(const char& val) { if (pos == SIZE) flush(); line[pos++] = val; } template ::value, int> = 0> void write_single(T val) { if (pos > (1 << 15) - 50) flush(); if (val == 0) { write_single('0'); return; } if (val < 0) { write_single('-'); val = -val; // todo min } size_t len = 0; while (val) { small[len++] = char('0' + (val % 10)); val /= 10; } for (size_t i = 0; i < len; i++) { line[pos + i] = small[len - 1 - i]; } pos += len; } void write_single(const string& s) { for (char c : s) write_single(c); } void write_single(const char* s) { size_t len = strlen(s); for (size_t i = 0; i < len; i++) write_single(s[i]); } template void write_single(const V& val) { auto n = val.size(); for (size_t i = 0; i < n; i++) { if (i) write_single(' '); write_single(val[i]); } } }; template struct ModInt { using M = ModInt; static constexpr uint get_mod() { return MD; } const static M G; uint v; ModInt(ll _v = 0) { set_v(uint(_v % MD + MD)); } M& set_v(uint _v) { v = (_v < MD) ? _v : _v - MD; return *this; } explicit operator bool() const { return v != 0; } M operator-() const { return M() - *this; } M operator+(const M& r) const { return M().set_v(v + r.v); } M operator-(const M& r) const { return M().set_v(v + MD - r.v); } M operator*(const M& r) const { return M().set_v(uint(ull(v) * r.v % MD)); } M operator/(const M& r) const { return *this * r.inv(); } M& operator+=(const M& r) { return *this = *this + r; } M& operator-=(const M& r) { return *this = *this - r; } M& operator*=(const M& r) { return *this = *this * r; } M& operator/=(const M& r) { return *this = *this / r; } bool operator==(const M& r) const { return v == r.v; } M pow(ll n) const { M x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; } M inv() const { return pow(MD - 2); } friend ostream& operator<<(ostream& os, const M& r) { return os << r.v; } }; // using Mint = ModInt<998244353>; // template<> const Mint Mint::G = Mint(3); template struct Comb { int max_n; V fact, ifact; Comb() {} Comb(int n) : max_n(n) { fact = ifact = V(n + 1); fact[0] = Mint(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 C(int n, int k) { if (n < k || n < 0) return Mint(0); assert(0 <= k && k <= n && n <= max_n); return fact[n] * ifact[k] * ifact[n - k]; } }; using Mint = ModInt; Mint i_mod = 430477711; // i_mod * i_mod == -1 using D = double; const D PI = acos(D(-1)); using Pc = complex; void fft(bool type, V& a) { int n = int(a.size()), s = 0; while ((1 << s) < n) s++; assert(1 << s == n); static V ep[30]; if (!ep[s].size()) { for (int i = 0; i < n; i++) { ep[s].push_back(polar(1, i * 2 * PI / n)); } } V b(n); for (int i = 1; i <= s; i++) { int w = 1 << (s - i); for (int y = 0; y < n / 2; y += w) { Pc now = ep[s][y]; if (type) now = conj(now); for (int x = 0; x < w; x++) { auto l = a[y << 1 | x]; auto u = now, v = a[y << 1 | x | w]; auto r = Pc(u.real() * v.real() - u.imag() * v.imag(), u.real() * v.imag() + u.imag() * v.real()); b[y | x] = l + r; b[y | x | n >> 1] = l - r; } } swap(a, b); } } V multiply(const V& a, const V& b) { int A = int(a.size()), B = int(b.size()); if (!A || !B) return {}; int lg = 0; while ((1 << lg) < A + B - 1) lg++; int N = 1 << lg; V ac(N), bc(N); for (int i = 0; i < A; i++) ac[i] = a[i]; for (int i = 0; i < B; i++) bc[i] = b[i]; fft(false, ac); fft(false, bc); for (int i = 0; i < N; i++) { ac[i] *= bc[i]; } fft(true, ac); V c(A + B - 1); for (int i = 0; i < A + B - 1; i++) { c[i] = ac[i] / D(N); } return c; } V multiply(const V& a, const V& b) { int A = int(a.size()), B = int(b.size()); if (!A || !B) return {}; int lg = 0; while ((1 << lg) < A + B - 1) lg++; int N = 1 << lg; V d(N); for (int i = 0; i < N; i++) d[i] = Pc(i < A ? a[i] : 0, i < B ? b[i] : 0); fft(false, d); for (int i = 0; i < N / 2 + 1; i++) { auto j = i ? (N - i) : 0; Pc x = Pc(d[i].real() + d[j].real(), d[i].imag() - d[j].imag()); Pc y = Pc(d[i].imag() + d[j].imag(), -d[i].real() + d[j].real()); d[i] = x * y / D(4); if (i != j) d[j] = conj(d[i]); } fft(true, d); V c(A + B - 1); for (int i = 0; i < A + B - 1; i++) { c[i] = d[i].real() / N; } return c; } template V multiply(const V& a, const V& b) { int A = int(a.size()), B = int(b.size()); if (!A || !B) return {}; int lg = 0; while ((1 << lg) < A + B - 1) lg++; int N = 1 << lg; VV x(K, V(N)), y(K, V(N)); for (int ph = 0; ph < K; ph++) { V z(N); for (int i = 0; i < N; i++) { D nx = 0, ny = 0; if (i < A) nx = (a[i].v >> (ph * SHIFT)) & ((1 << SHIFT) - 1); if (i < B) ny = (b[i].v >> (ph * SHIFT)) & ((1 << SHIFT) - 1); z[i] = Pc(nx, ny); } fft(false, z); for (int i = 0; i < N; i++) { z[i] *= 0.5; } for (int i = 0; i < N; i++) { int j = (i) ? N - i : 0; x[ph][i] = Pc(z[i].real() + z[j].real(), z[i].imag() - z[j].imag()); y[ph][i] = Pc(z[i].imag() + z[j].imag(), -z[i].real() + z[j].real()); } } VV z(K, V(N)); for (int xp = 0; xp < K; xp++) { for (int yp = 0; yp < K; yp++) { int zp = (xp + yp) % K; for (int i = 0; i < N; i++) { if (xp + yp < K) { z[zp][i] += x[xp][i] * y[yp][i]; } else { z[zp][i] += x[xp][i] * y[yp][i] * Pc(0, 1); } } } } for (int ph = 0; ph < K; ph++) { fft(true, z[ph]); } V c(A + B - 1); Mint base = 1; for (int ph = 0; ph < 2 * K - 1; ph++) { for (int i = 0; i < A + B - 1; i++) { if (ph < K) { c[i] += Mint(ll(round(z[ph][i].real() / N))) * base; } else { c[i] += Mint(ll(round(z[ph - K][i].imag() / N))) * base; } } base *= 1 << SHIFT; } return c; } #include #include #include struct Random { private: // Use xoshiro256** // Refereces: http://xoshiro.di.unimi.it/xoshiro256starstar.c static uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } std::array s; uint64_t next() { const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; const uint64_t t = s[1] << 17; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = rotl(s[3], 45); return result_starstar; } // random choice from [0, upper] uint64_t next(uint64_t upper) { if (!(upper & (upper + 1))) { // b = 00..0011..11 return next() & upper; } int lg = 63 - __builtin_clzll(upper); uint64_t mask = (lg == 63) ? ~0ULL : (1ULL << (lg + 1)) - 1; while (true) { uint64_t r = next() & mask; if (r <= upper) return r; } } public: Random(uint64_t seed = 0) { // Use splitmix64 // Reference: http://xoshiro.di.unimi.it/splitmix64.c for (int i = 0; i < 4; i++) { uint64_t z = (seed += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; s[i] = z ^ (z >> 31); } } // random choice from [lower, upper] template T uniform(T lower, T upper) { assert(lower <= upper); return T(lower + next(uint64_t(upper - lower))); } bool uniform_bool() { return uniform(0, 1) == 1; } double uniform01() { uint64_t v = next(1ULL << 63); return double(v) / (1ULL << 63); } // generate random lower string that length = n std::string lower_string(size_t n) { std::string res = ""; for (size_t i = 0; i < n; i++) { res += uniform('a', 'z'); } return res; } // random shuffle template void shuffle(Iter first, Iter last) { if (first == last) return; // Reference and edit: // cpprefjp - C++日本語リファレンス // (https://cpprefjp.github.io/reference/algorithm/shuffle.html) int len = 1; for (auto it = first + 1; it != last; it++) { len++; int j = uniform(0, len - 1); if (j != len - 1) iter_swap(it, first + j); } } // generate random permutation that length = n template std::vector perm(size_t n) { std::vector idx(n); std::iota(idx.begin(), idx.end(), T(0)); shuffle(idx.begin(), idx.end()); return idx; } template std::vector choice(size_t n, T lower, T upper) { assert(n <= upper - lower + 1); std::set res; while (res.size() < n) res.insert(uniform(lower, upper)); return {res.begin(), res.end()}; } } global_gen; Random get_random_gen() { return Random(chrono::steady_clock::now().time_since_epoch().count()); } template struct Poly { V v; Poly(const V& _v = {}) : v(_v) { shrink(); } void shrink() { while (v.size() && !v.back()) v.pop_back(); } int size() const { return int(v.size()); } D freq(int p) const { return (p < size()) ? v[p] : D(0); } Poly operator+(const Poly& r) const { auto n = max(size(), r.size()); V res(n); for (int i = 0; i < n; i++) res[i] = freq(i) + r.freq(i); return res; } Poly operator-(const Poly& r) const { int n = max(size(), r.size()); V res(n); for (int i = 0; i < n; i++) res[i] = freq(i) - r.freq(i); return res; } Poly operator*(const Poly& r) const { return {multiply(v, r.v)}; } Poly operator*(const D& r) const { int n = size(); V res(n); for (int i = 0; i < n; i++) res[i] = v[i] * r; return res; } Poly operator/(const D &r) const{ return *this * r.inv(); } Poly operator/(const Poly& r) const { if (size() < r.size()) return {{}}; int n = size() - r.size() + 1; return (rev().pre(n) * r.rev().inv(n)).pre(n).rev(n); } Poly operator%(const Poly& r) const { return *this - *this / r * r; } Poly operator<<(int s) const { V res(size() + s); for (int i = 0; i < size(); i++) res[i + s] = v[i]; return res; } Poly operator>>(int s) const { if (size() <= s) return Poly(); V res(size() - s); for (int i = 0; i < size() - s; i++) res[i] = v[i + s]; return res; } Poly& operator+=(const Poly& r) { return *this = *this + r; } Poly& operator-=(const Poly& r) { return *this = *this - r; } Poly& operator*=(const Poly& r) { return *this = *this * r; } Poly& operator*=(const D& r) { return *this = *this * r; } Poly& operator/=(const Poly& r) { return *this = *this / r; } Poly& operator/=(const D &r) {return *this = *this/r;} Poly& operator%=(const Poly& r) { return *this = *this % r; } Poly& operator<<=(const size_t& n) { return *this = *this << n; } Poly& operator>>=(const size_t& n) { return *this = *this >> n; } Poly pre(int le) const { return {{v.begin(), v.begin() + min(size(), le)}}; } Poly rev(int n = -1) const { V res = v; if (n != -1) res.resize(n); reverse(res.begin(), res.end()); return res; } Poly diff() const { V res(max(0, size() - 1)); for (int i = 1; i < size(); i++) res[i - 1] = freq(i) * i; return res; } Poly inte() const { V res(size() + 1); for (int i = 0; i < size(); i++) res[i + 1] = freq(i) / (i + 1); return res; } // f * f.inv() = 1 + g(x)x^m Poly inv(int m) const { Poly res = Poly({D(1) / freq(0)}); for (int i = 1; i < m; i *= 2) { res = (res * D(2) - res * res * pre(2 * i)).pre(2 * i); } return res.pre(m); } Poly exp(int n) const { assert(freq(0) == 0); Poly f({1}), g({1}); for (int i = 1; i < n; i *= 2) { g = (g * 2 - f * g * g).pre(i); Poly q = diff().pre(i - 1); Poly w = (q + g * (f.diff() - f * q)).pre(2 * i - 1); f = (f + f * (*this - w.inte()).pre(2 * i)).pre(2 * i); } return f.pre(n); } Poly log(int n) const { assert(freq(0) == 1); auto f = pre(n); return (f.diff() * f.inv(n - 1)).pre(n - 1).inte(); } Poly sqrt(int n) const { assert(freq(0) == 1); Poly f = pre(n + 1); Poly g({1}); for (int i = 1; i < n; i *= 2) { g = (g + f.pre(2 * i) * g.inv(2 * i)) / 2; } return g.pre(n + 1); } Poly pow_mod(ll n, const Poly& mod) { Poly x = *this, r = {{1}}; while (n) { if (n & 1) r = r * x % mod; x = x * x % mod; n >>= 1; } return r; } friend ostream& operator<<(ostream& os, const Poly& p) { if (p.size() == 0) return os << "0"; for (auto i = 0; i < p.size(); i++) { if (p.v[i]) { os << p.v[i] << "x^" << i; if (i != p.size() - 1) os << "+"; } } return os; } }; template struct MultiEval { using NP = MultiEval*; NP l, r; V que; int sz; Poly mul; MultiEval(const V& _que, int off, int _sz) : sz(_sz) { if (sz <= 100) { que = {_que.begin() + off, _que.begin() + off + sz}; mul = {{1}}; for (auto x : que) mul *= {{-x, 1}}; return; } l = new MultiEval(_que, off, sz / 2); r = new MultiEval(_que, off + sz / 2, sz - sz / 2); mul = l->mul * r->mul; } MultiEval(const V& _que) : MultiEval(_que, 0, int(_que.size())) {} void query(const Poly& _pol, V& res) const { if (sz <= 100) { for (auto x : que) { Mint sm = 0, base = 1; for (int i = 0; i < _pol.size(); i++) { sm += base * _pol.freq(i); base *= x; } res.push_back(sm); } return; } auto pol = _pol % mul; l->query(pol, res); r->query(pol, res); } V query(const Poly& pol) const { V res; query(pol, res); return res; } }; template Poly berlekamp_massey(const V& s) { int n = int(s.size()); V b = {Mint(-1)}, c = {Mint(-1)}; Mint y = Mint(1); for (int ed = 1; ed <= n; ed++) { int l = int(c.size()), m = int(b.size()); Mint x = 0; for (int i = 0; i < l; i++) { x += c[i] * s[ed - l + i]; } b.push_back(0); m++; if (!x) continue; Mint freq = x / y; if (l < m) { // use b auto tmp = c; c.insert(begin(c), m - l, Mint(0)); for (int i = 0; i < m; i++) { c[m - 1 - i] -= freq * b[m - 1 - i]; } b = tmp; y = x; } else { // use c for (int i = 0; i < m; i++) { c[l - 1 - i] -= freq * b[m - 1 - i]; } } } return c; } template Mint sparse_det(const VV& g) { int n = int(g.size()); if (n == 0) return 1; auto rand_v = [&]() { V res(n); for (int i = 0; i < n; i++) { res[i] = Mint(global_gen.uniform(1, Mint(-1).v)); } return res; }; V c = rand_v(), l = rand_v(), r = rand_v(); // l * mat * r V buf(2 * n); for (int fe = 0; fe < 2 * n; fe++) { for (int i = 0; i < n; i++) { buf[fe] += l[i] * r[i]; } for (int i = 0; i < n; i++) { r[i] *= c[i]; } V tmp(n); for (int i = 0; i < n; i++) { for (auto e : g[i]) { tmp[i] += r[e.to] * e.f; } } r = tmp; } auto u = berlekamp_massey(buf); if (u.size() != n + 1) return sparse_det(g); auto acdet = u.freq(0) * Mint(-1); if (n % 2) acdet *= Mint(-1); if (!acdet) return 0; Mint cdet = 1; for (int i = 0; i < n; i++) cdet *= c[i]; return acdet / cdet; } using MPol = Poly; Scanner sc = Scanner(stdin); Printer pr = Printer(stdout); int main() { assert(i_mod * i_mod == Mint(-1)); // h(m) = 1, 1, -1, -1, 1, 1, -1, -1, ... // f(x) = sum_{j = 1} (j + 1) x^j // g(x) = sum_{i = 0}^{N} h(i) * f(x)^i * C(N, i) * (N - i)! // = N! sum_{i = 0}^{N} h(i) * f(x)^i / i! // = N! sum_{i = 0} h(i) * f(x)^i / i! (because f(0) == 0) // g(x) / N! = sin(f(x)) + cos(f(x)) // 2i * sin(f(x)) = e^(i f(x)) - e^(- i f(x)) // 2 * cos(f(x)) = e^(i f(x)) + e^(- i f(x)) int N; sc.read(N); Comb C(N + 10); V _f(N + 1); for (int i = 1; i <= N; i++) { _f[i] = Mint(i + 1) * Mint(i + 1); } auto f = MPol(_f); auto ei = (f * i_mod).exp(N + 1); // e^(i f(x)) auto eni = (f * -i_mod).exp(N + 1); // e^(- i f(x)) auto sinx = (ei - eni) / (Mint(2) * i_mod); auto cosx = (ei + eni) / Mint(2); auto g = sinx + cosx; /*MPol g; for (int i = 0; i <= N; i++) { Mint h = (i % 4 < 2 ? Mint(1) : Mint(-1)); MPol f2 = MPol({1, 0}); for (int j = 0; j < i; j++) { f2 *= f; } f2 = f2.pre(N + 1); dbg(i, f2); g += f2 * h * C.ifact[i]; }*/ g *= C.fact[N]; ; for (int i = 1; i <= N; i++) { pr.writeln(g.freq(i).v); } return 0; }