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;
}
posted @ 2022-09-28 16:37  Smallbasic  阅读(34)  评论(0)    收藏  举报