【题解】洛谷 P6295 有标号 DAG 计数【生成函数 多项式】

题目链接

题意

求有标号弱连通 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;
}
知识共享许可协议
若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
原文地址:https://www.cnblogs.com/wallbreaker5th/p/14151445.html