1. 程式人生 > 實用技巧 >【題解】洛谷 P6295 有標號 DAG 計數【生成函式 多項式】

【題解】洛谷 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;
}