P6295 有标号DAG计数
先不考虑弱联通的条件,设 \(f(n)\) 表示 \(n\) 个点的DAG个数,考虑容斥,枚举一层有 \(i\) 个入度为 \(0\) 的点:
\[f(n)=\sum_{i=1}^n (-1)^{i+1} \binom{n}{i} 2^{i(n-i)} f(n-i)
\]
这个式子不怎么好卷。显然 \(\binom{n}{i}\) 可以拆,对于 \(2^{i(n-i)}\),我们有经典trick: \(ij=\binom{i+j}{2}-\binom{i}{2}-\binom{j}{2}\),于是
\[2^{i(n-i)}={2^{\binom{n}{2}}\over 2^{\binom{i}{2}} 2^{\binom{n-i}{2}}}
\]
所以:
\[f(n)=\sum_{i=1}^n (-1)^{i+1} \binom{n}{i} 2^{i(n-i)} f(n-i)\rightarrow {f(n)\over 2^{\binom{n}{2}}n!}=\sum_{i=1}^n {(-1)^{i+1}\over 2^{\binom{i}{2}}i!} {f(n-i)\over 2^{\binom{n-i}{2}}(n-i)!}
\]
我们发现两边含 \(f\) 的部分的形式都相同,实际上就是P4721的套路。
之后我们考虑加上弱联通图的限制,设 \(G(x)\) 表示答案的 EGF,\(e^{G(x)}\) 的泰勒展开:
\[e^{G(x)}=\sum_{i=0}^{\infty} {G^i(x)\over i!}
\]
考虑 \([{x^n\over n!}]e^{G(x)}\) 的组合意义,带到展开式里发现实际上是枚举了 \(i\) 个弱联通图组合到一起,所有的方案加起来,实际上就是 \(n\) 阶有向图的个数。设 \(F(x)\) 为之前的 \(f\) 的EGF,我们有:
\[e^{G(x)}=F(x) \rightarrow F(x)=\ln G(x)
\]
#include <bits/stdc++.h>
using namespace std;
#define pi pair<int,int>
#define mp make_pair
#define poly vector<int>
const int N = 3e5 + 5, mod = 998244353, G = 3, I = 86583718;
const int add(int a, int b) { return (a + b) >= mod ? a + b - mod : a + b; }
const int sub(int a, int b) { return a < b ? a - b + mod : a - b; }
const int mul(int a, int b) { return (1ll * a * b) % mod; }
const int power(int a, int b, int p = mod) {
int t = 1, y = a, k = b;
while (k) {
if (k & 1) t = (1ll * t * y) % p;
y = (1ll * y * y) % p; k >>= 1;
} return t;
}
const int inv2 = power(2, mod - 2), inv2I = power(mul(2, I), mod - 2), Gi = power(G, mod - 2);
inline int read() {
register int s = 0, f = 1; register char ch = getchar();
while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
return s * f;
}
inline void otp(int x) {
(x >= 10) ? otp(x / 10), putchar((x % 10) ^ 48) : putchar(x ^ 48);
}
inline void FFT(int *a, int len, int typ) {
for (int i = 0, j = 0, k; i < len; ++i) {
if (i < j) swap(a[i], a[j]);
for (k = len >> 1; k & j; k >>= 1) j ^= k;
j ^= k;
}
for (int mid = 1; mid < len; mid <<= 1) {
int wn = power(typ == 1 ? G : Gi, (mod - 1) / (mid << 1));
for (int j = 0; j < len; j += mid << 1) {
int bas = 1;
for (int k = 0; k < mid; ++k, bas = mul(bas, wn)) {
int x = a[j + k], y = ::mul(bas, a[j + mid + k]);
a[j + k] = ::add(x, y);
a[j + mid + k] = ::sub(x, y);
}
}
}
if (!typ) {
const int iv = power(len, mod - 2);
for (int i = 0; i < len; ++i)
a[i] = ::mul(a[i], iv);
}
}
inline int max_(int a, int b) {
return a > b ? a : b;
}
inline int min_(int a, int b) {
return a < b ? a : b;
}
inline poly add(poly a, int b) {
for (int i = 0; i < a.size(); ++i) a[i] = ::add(a[i], b);
return a;
}
inline poly sub(poly a, int b) {
for (int i = 0; i < a.size(); ++i) a[i] = ::sub(a[i], b);
return a;
}
inline poly mul(poly a, int b) {
for (int i = 0; i < a.size(); ++i) a[i] = ::mul(a[i], b);
return a;
}
inline poly div(poly a, int b) {
b = ::power(b, mod - 2);
for (int i = 0; i < a.size(); ++i) a[i] = ::mul(a[i], b);
return a;
}
inline poly add(poly a, poly b) {
a.resize(max_(a.size(), b.size()));
for (int i = 0; i < b.size(); ++i) a[i] = ::add(a[i], b[i]);
return a;
}
inline poly sub(poly a, poly b) {
a.resize(max_(a.size(), b.size()));
for (int i = 0; i < b.size(); ++i) a[i] = ::sub(a[i], b[i]);
return a;
}
inline poly mul(poly a, poly b) {
int p = a.size() + b.size() - 1; int len = 1 << (int)ceil(log2(p));
a.resize(len); b.resize(len);
FFT(&a[0], len, 1); FFT(&b[0], len, 1);
for (int i = 0; i < len; ++i)
a[i] = ::mul(a[i], b[i]);
FFT(&a[0], len, 0); a.resize(p);
return a;
}
inline poly inv(poly a, int len) {
if (len == 1) return poly(1, power(a[0], mod - 2));
int n = 1 << ((int)ceil(log2(len)) + 1);
poly x = inv(a, len + 1 >> 1), y;
x.resize(n); y.resize(n);
for (int i = 0; i < len; ++i) y[i] = a[i];
FFT(&x[0], n, 1); FFT(&y[0], n, 1);
for (int i = 0; i < n; ++i) x[i] = ::mul(x[i], ::sub(2, ::mul(x[i], y[i])));
FFT(&x[0], n, 0);
x.resize(len);
return x;
}
inline poly inv(poly a) {
return inv(a, a.size());
}
inline poly rev(poly a) {
reverse(a.begin(), a.end());
return a;
}
inline poly div(poly a, poly b) {
if (a.size() < b.size()) return poly(1, 0);
int p = a.size() - b.size() + 1;
poly ra = rev(a), rb = rev(b);
ra.resize(p), rb.resize(p);
ra = mul(ra, inv(rb));
ra.resize(p);
return rev(ra);
}
inline poly remainder(poly a, poly b) {
if (a.size() < b.size()) return a;
poly c = div(a, b), d = sub(a, mul(b, c));
while (d.size() && !d.back()) d.pop_back();
if (!d.size()) d = poly(1, 0);
return d;
}
inline poly det(poly a) {
int n = a.size();
for (int i = 1; i < n; ++i) a[i - 1] = ::mul(a[i], i);
a.resize(n - 1);
return a;
}
inline poly inter(poly a) {
int n = a.size(); a.resize(n + 1);
for (int i = n; i >= 1; --i)
a[i] = ::mul(a[i - 1], power(i, mod - 2));
a[0] = 0; return a;
}
inline poly ln(poly a) {
int n = a.size();
a = inter(mul(det(a), inv(a)));
a.resize(n); return a;
}
inline poly exp(poly a, int len) {
if (len == 1) return poly(1, 1);
poly x = exp(a, len + 1 >> 1); x.resize(len);
poly y = ln(x);
for (int i = 0; i < len; ++i) y[i] = ::sub(a[i], y[i]);
++y[0]; x = mul(x, y); x.resize(len);
return x;
}
inline poly exp(poly a) {
return exp(a, a.size());
}
inline poly polysqrt(poly a, int len) {
poly x, res, F, tmp; x.push_back(1);
for (int L = 1; L < (len << 1); L <<= 1) {
F = a; F.resize(L << 1);
tmp = mul(x, x); tmp.resize(L << 1);
res = inv(::mul(x, 2));
res.resize(L << 1);
res = mul(res, add(F, tmp));
res.resize(L << 1);
x = res;
} res.resize(len);
return res;
}
inline poly polysqrt(poly a) {
return ::polysqrt(a, a.size());
}
inline poly cos(poly a) {
return mul(add(exp(mul(a, I)), exp(mul(a, mod - I))), inv2);
}
inline poly sin(poly a) {
return mul(sub(exp(mul(a, I)), exp(mul(a, mod - I))), power(I << 1, mod - 2));
}
inline poly __power(poly a, int k) {
a = ln(a);
for (int i = 0; i < a.size(); ++i) a[i] = (1ll * k * a[i]) % mod;
a = exp(a);
return a;
}
inline poly polypow(poly a, int k, int k2) { // k % mod, k % mod - 1
int len = a.size();
if (a[0] == 1) return __power(a, k);
int p = 0;
while (a[p] == 0) ++p;
int t = a[p];
for (int i = 0; i < a.size() - p; ++i) a[i] = a[i + p];
a.resize(a.size() - p);
for (int i = 0; i < a.size(); ++i) a[i] = mul(a[i], power(t, mod - 2));
a = __power(a, k);
t = power(t, k2);
for (int i = 0; i < a.size(); ++i) a[i] = mul(a[i], t);
poly b; b.resize(len);
for (int i = a.size() - 1; ~i; --i)
if (i + 1ll * p * k < len) b[i + p * k] = a[i];
return b;
}
inline poly cyclic(poly g, int f0) {
for (int i = 0; i < g.size(); ++i)
g[i] = ::sub(1, g[i]);
g[0] = 1;
return mul(g, f0);
}
int fac[N], ifac[N], inver[N], tim[N];
inline poly trans(poly a, int c) {
poly p;
for (register int i = 0; i < a.size(); ++i) {
a[i] = (1ll * a[i] * fac[i]) % mod;
p.push_back((1ll * power(c, i) * ifac[i]) % mod);
} int n = a.size(); reverse(a.begin(), a.end()); a = mul(a, p);
a.resize(n); reverse(a.begin(), a.end());
for (register int i = 0; i < a.size(); ++i)
a[i] = (1ll * a[i] * ifac[i]) % mod;
return a;
}
inline poly stir1R(int n) {
poly t, y; int k = n, tt = 1;
t.push_back(1); y.push_back(0); y.push_back(1);
int sum = 0;
while (k) {
if (k & 1) {
sum += tt;
t = mul(trans(t, tt), y);
t.resize(sum + 1);
} y = mul(trans(y, tt), y);
tt <<= 1; //y len
y.resize(tt + 1);
k >>= 1;
} return t;
}
inline poly stir2R(int n) {
poly a, b;
for (int i = 0; i <= n; ++i) {
a.push_back((1ll * power(i, n) * ifac[i]) % mod);
b.push_back(ifac[i]); if (i & 1) b[i] = -b[i] + mod;
if (b[i] >= mod) b[i] -= mod;
} return mul(a, b);
}
inline poly stir1L(int n, int k) {
poly a; a.resize(n + 1);
for (int i = 0; i <= n; ++i)
a[i] = 1;
a = ln(a);
a = polypow(a, k, k);
for (int i = 0; i <= n; ++i)
a[i] = mul(fac[i], mul(a[i], ifac[k]));
return a;
}
inline poly stir2L(int n, int k) {
poly a; a.resize(n + 1);
for (int i = 1; i <= n; ++i) a[i] = ifac[i];
a = polypow(a, k, k);
for (int i = 0; i <= n; ++i)
a[i] = mul(fac[i], mul(ifac[k], a[i]));
return a;
}
inline poly partition(int n, int m) {
poly p; p.resize(n + 1);
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n / i; ++j)
p[i * j] = sub(p[i * j], (1ll * fac[j - 1] * ifac[j]) % mod);
} return inv(exp(p));
}
int n, m;
poly a;
inline void prepare(int NN) {
fac[0] = 1;
for (int i = 1; i <= NN; ++i) fac[i] = ::mul(fac[i - 1], i);
ifac[NN] = power(fac[NN], mod - 2);
for (int i = NN - 1; ~i; --i) ifac[i] = ::mul(i + 1, ifac[i + 1]);
for (int i = 1; i <= NN; ++i)
inver[i] = ::mul(ifac[i], fac[i - 1]);
}
int main() {
n = read(); poly f, g;
f.resize(n + 1); g.resize(n + 1);
prepare(n);
for (int i = 1; i <= n; ++i) {
g[i] = mul(ifac[i], power(power(2, (1ll * i * (i - 1) / 2ll) % (mod - 1)), mod - 2));
g[i] = (i & 1) ? (mod - g[i]) % mod : g[i];
} g[0] = 1;
f = inv(g);
for (int i = 0; i <= n; ++i) {
f[i] = mul(f[i], power(2, (1ll * i * (i - 1) / 2ll) % (mod - 1)));
}
f = ln(f);
for (int i = 1; i <= n; ++i) otp(mul(f[i], fac[i])), putchar('\n');
return 0;
}