题意
求有标号弱连通 DAG 的数量。(nleq 10^5)
题解
首先考虑不要求连通时的做法:设 (i) 个点时的答案为 (g_i),对应的生成函数为 (F(x))。枚举至少有多少个点的入度为 (0),选出这些点,决定连边方式,并乘上容斥系数:
[g_i=sum_{j=1}^n dbinom{i}{j} 2^{j(i-j)} g(i-j) (-1)^{j+1}
]
将 (dbinom{i}{j}) 拆成 (dfrac{i!}{j!(i-j)!}),将 (j(i-j)) 拆成 (dbinom{i}{2}-dbinom{j}{2}-dbinom{i-j}{2}),上式显然是一个卷积,可以写作 (G=Gcdot A+1),解出 (G)。
(ln(G)) 即为连通时的答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
// 读优、阶乘逆元预处理、多项式板子等略。
// 多项式板子整体架构类似于 EI 的第二代多项式模板(https://blog.csdn.net/EI_Captain/article/details/88628618)
int main(){
int n(io);
Poly A(zeroes(n));
int p2=1,pp2=1;
for(int i=1;i<=n;i++){
pp2=pp2*1ll*p2%mod;
(p2&1)?(p2=(p2+mod)>>1):(p2>>=1);
A[i]=pp2*1ll*simp.ifac(i)%mod;
if(i%2==0)A[i]=mod-A[i];
}
Poly G=(Poly(1)-A).inv();
p2=1,pp2=1;
for(int i=1;i<=n;i++){
pp2=pp2*1ll*p2%mod;
p2=norm(p2<<1);
G[i]=G[i]*1ll*pp2%mod;
}
Poly F=G.ln();
for(int i=1;i<=n;i++){
io.putint(F[i]*1ll*simp.fac(i)%mod%mod,'
');
}
return 0;
}