令 f(n) 表示 n 个点的弱连通 DAG 数量。给定 T,输出 f(1)modp,f(2)modp,⋯,f(T)modp。其中 p=998,244,353。
1≤T≤105。称一个有向图是弱连通的,当且仅当将所有有向边替换为无向边后的图连通。
令 F^(z)=∑i≥0i!f(i)zi,g(n) 表示 n 个点的 DAG 数量,G(z)=∑i≥0g(i)zi,G^(z)=∑i≥0i!g(i)zi。
则根据多项式 exp 的组合意义有 exp(F^(z))=G^(z),即 F^(z)=lnG^(z)。故只要快速求出 g(n) 就可以快速求出 f(n)。
考虑如何求出 g(n),有一个 naive 的 dp:
g(n)=i=1∑n(in)g(n−i)2i(n−i)
大意是枚举入度为 0 的点有 i 个,这样的选法有 (in) 种,剩余的 DAG 有 g(n−i) 种方案,入度为 0 的点 i 连向其余点的边有 2i(n−i) 种选法。但是这样有一定问题,就是剩余点中,如果有若干点是剩余 DAG 的入度为 0 点,且与原 DAG 的入度为 0 的点没有边相连,那么这一部分会算重。换句话说,i 不能保证恰好,只能保证至少。
遇到这种困境,不妨容斥,也就是需要找到容斥系数函数 ϵ(x) 使得对于任意 S 有 ∑T⊆S,T=∅ϵ(∣T∣),可以发现 ϵ(x)=(−1)x+1 就满足条件。因此可以得到一个正确的 dp:
g(n)=i=1∑n(in)g(n−i)(−1)i+12i(n−i)
直接转移,时间复杂度 O(T2) 难以接受,不过这个形式如果没有 2i(n−i) 的话很像卷积,因此尝试对 2i(n−i) 变形。
注意到下面的恒等式:
nm=(2n+m)−(2n)−(2m)
证明是平凡的。
根据这个恒等式,我们对原式变形:
g(n)=i=1∑n(in)(−1)i+1⋅g(n−i)⋅2(2i)2(2n−i)2(2n)n!⋅2(2n)g(n)=i=1∑ni!⋅2(2i)(−1)i+1⋅2(2n−i)⋅(n−i)!g(n−i)
得到了标准卷积形式。不妨记 p(n)=n!⋅2(2n)g(n),q(n)=n!⋅2(2n)(−1)n+1,P(z)=∑i≥0p(i)zi,Q(z)=∑i≥1q(i)zi,则得到:
p(n)=i=1∑nq(i)p(n−i)⟹P(z)=P(z)Q(z)+1
注意那个 +1,由于 P(0)=1,Q(0)=0,所以 [z0](P(z)⋅Q(z))=1,故要补上一个 1 来修正常数项。
解得 P(z)=1−Q(z)1。而 q(n) 是易求的,故只要做一遍多项式求逆,然后做一遍多项式对数函数,就可以求出答案。
时间复杂度 O(TlogT)。
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
int Add(int x, int y){ return (x + y) >= mod ? (x + y - mod) : (x + y); }
int Sub(int x, int y){ return (x - y) < 0 ? (x - y + mod) : (x - y); }
int Mul(int x, int y){ return 1ll * x * y % mod; }
int fastpow(int x, int y){
int ret = 1;
for(;y;y>>=1,x=Mul(x,x)){
if(y & 1) ret = Mul(ret, x);
}
return ret;
}
int Inv(int x){ return fastpow(x, mod-2); }
namespace poly {
// ... poly template ...
}
using poly::Poly;
const int N = 1e5 + 5;
int n, fact[N];
int magic(int i){
return fastpow(2, ((1ll * i * (i - 1)) >> 1) % (mod - 1));
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n, fact[0] = 1;
for(int i=1;i<=n;i++) fact[i] = Mul(fact[i - 1], i);
Poly Q(n + 1);
for(int i=1;i<=n;i++){
Q[i] = Inv(Mul(fact[i], magic(i)));
if(!(i & 1)) Q[i] = Sub(0, Q[i]);
}
Poly P = ~(1 - Q), G(n + 1);
for(int i=0;i<=n;i++) G[i] = Mul(P[i], magic(i));
Poly F = G.ln();
for(int i=1;i<=n;i++) cout << Mul(F[i], fact[i]) << '\n';
return 0;
}
// Written by xiezheyuan
相关 OEIS:
- A082402 Number of n-node labeled weakly connected acyclic digraphs.。前几项为 0,1,2,18,446,26430,3596762。
- A003024 Number of acyclic digraphs (or DAGs) with n labeled nodes.。前几项为 1,1,3,25,543,29281,3781503。