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

题目链接

题意

求有标号弱连通 DAG 的数量。\(n\leq 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=G\cdot 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,'\n');
    }
    return 0;
}
posted @ 2020-12-17 19:26  破壁人五号  阅读(98)  评论(0编辑  收藏  举报