题解 P5828【边双连通图计数】

$\text{Link}$

题意

求 $n$ 个点的有标号边双连通图数量,对 $998244353$ 取模。

$1\le n\le10^5$

思路

前置

有标号无向连通图计数扩展拉格朗日反演


设有根无向连通图的 $\text{EGF}$ 为 $F(x)$,有根边双连通图的 $\text{EGF}$ 为 $G(x)$。

我们显然可以使用有标号无向连通图的 $\text{EGF}$ 乘上 $n$ 以得到 $F(x)$,于是考虑用 $F,G$ 互相表示。

对于一个有根无向连通图,我们可以枚举其根所在的边双大小,再算出所有连向其它部分的边的 $\text{EGF}$。

对于一条边,我们可以有:其挂着一个无向连通图;可以连在边双中任意一个点上。所以一条边的 $\text{EGF}$ 为 $nF(x)$。(其中 $n$ 为根节点所在的边双的大小)

由于连的多条边与一条边也可看为集合与元素的关系,可以直接得到$$\begin{aligned} F(x)&=\sum_{n\ge1}g_n\exp(nF(x))\frac{x^n}{n!}\\ &=\sum_{n\ge1}\frac{g_n}{n!}x^ne^{nF(x)}\\ &=\sum_{n\ge1}\frac{g_n}{n!}x^n{e^{F(x)}}^n\\ &=\sum_{n\ge1}\frac{g_n}{n!}\left(x\exp(F(x))\right)^n\\ &=G(x\exp(F(x))) \end{aligned}$$ 令 $H(x)=x\exp(F(x))$,有 $F(x)=G(H(x))$,根据扩展拉格朗日反演有$$\begin{aligned} [x^n]G(x)&=\frac 1 n\cdot[x^{n-1}]F'(x)\frac{x^n}{H^n(x)}\\ &=\frac 1 n\cdot[x^{n-1}]F'(x)\exp(-nF(x)) \end{aligned} $$ 至此直接求解即可。

时间复杂度 $O(n\log n)$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int mod=998244353,N=524288+10;
namespace Poly{
    int n,m,a[N],b[N],c[N],s[N],ss[N],d[N],e[N];
    int f[N],g[N],h[N],F[N],tmp1[N],tmp2[N];
    int rev[N],inv[N],fac[N],ifac[N],G[19][N],lim;
    inline void init(int n,int mode=1){
        if(mode){
            int l=0;
            for(lim=1;lim<n;lim<<=1)l++;
            for(int i=1;i<lim;i++)
                rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        }else{
            for(lim=1;lim<n;lim<<=1);
        }
    }
    inline int qpow(int x,int y){
        int res=1;
        while(y){
            if(y&1) res=1ll*res*x%mod;
            x=1ll*x*x%mod;
            y>>=1;
        }
        return res;
    }
    inline void Prefix(int n){
        inv[1]=1;
        for(int i=2;i<=n;i++)
            inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
        fac[0]=1;
        for(int i=1;i<=n;i++)
            fac[i]=1ll*fac[i-1]*i%mod;
        ifac[n]=qpow(fac[n],mod-2);
        for(int i=n;i>=1;i--)
            ifac[i-1]=1ll*ifac[i]*i%mod;
        for(int i=1,p=1;i<=18;i++,p<<=1){
            G[i][0]=1;
            G[i][1]=qpow(3,mod-1>>i);
            for(int j=2;j<p;j++)
                G[i][j]=1ll*G[i][j-1]*G[i][1]%mod;
        }
    }
    inline void NTT(int *a,int t){
        for(int i=0;i<lim;i++)
            if(i<rev[i])
                swap(a[i],a[rev[i]]);
        for(int i=1,t=1;i<lim;i<<=1,t++){
            for(int j=0;j<lim;j+=i<<1){
                int t1,t2;
                for(int k=0;k<i;k++){
                    t1=a[j+k];
                    t2=1ll*G[t][k]*a[i+j+k]%mod;
                    a[j+k]=(t1+t2)%mod;
                    a[i+j+k]=(t1-t2+mod)%mod;
                }
            }
        }
        if(t==1) return ;
        int Inv=qpow(lim,mod-2);
        reverse(a+1,a+lim);
        for(int i=0;i<lim;i++)
            a[i]=1ll*a[i]*Inv%mod;
    }
    inline void Inv(int *a,int *b,int n){
        if(n==1){
            b[0]=qpow(a[0],mod-2);
            return ;
        }
        Inv(a,b,n+1>>1);
        init(n<<1);
        for(int i=0;i<n;i++)
            c[i]=a[i];
        for(int i=n;i<lim;i++)
            c[i]=0;
        NTT(c,1),NTT(b,1);
        for(int i=0;i<lim;i++)
            b[i]=1ll*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;
        NTT(b,-1);
        for(int i=n;i<lim;i++)
            b[i]=0;
    }
    inline void Mul(int *a,int *b,int n){
        init(n<<1);
        memset(c,0,lim<<2);
        memcpy(c,b,n<<2);
        NTT(a,1),NTT(c,1);
        for(int i=0;i<lim;i++)
            a[i]=1ll*a[i]*c[i]%mod;
        NTT(a,-1);
    }
    inline void Der(int *a,int *b,int n){
        for(int i=1;i<n;i++)
            b[i-1]=1ll*i*a[i]%mod;
        b[n-1]=0;
    }
    inline void Int(int *a,int *b,int n){
        for(int i=1;i<n;i++)
            b[i]=1ll*a[i-1]*inv[i]%mod;
        b[0]=0;
    }
    inline void polyln(int *a,int *b,int n){
        static int p[N];
        memset(p,0,n<<3);
        memset(d,0,n<<3);
        Der(a,p,n);
        Inv(a,d,n);
        Mul(p,d,n);
        Int(p,b,n);
    }
    inline void Log(int n,int *f,int *g){
        init(n);
        polyln(f,g,lim);
        for(int i=n;i<lim;i++)
            g[i]=0;
    }
    inline void polyexp(int n,int *a,int *b){
        if(n==1){
            b[0]=1;
            return ;
        }
        polyexp(n+1>>1,a,b);
        Log(n,b,s);
        for(int i=0;i<n;i++)
            s[i]=a[i]>=s[i]?a[i]-s[i]:a[i]+mod-s[i];
        for(int i=n;i<lim;i++)
            b[i]=s[i]=0;
        s[0]++;
        NTT(s,1),NTT(b,1);
        for(int i=0;i<lim;i++)
            b[i]=1ll*b[i]*s[i]%mod;
        NTT(b,-1);
        for(int i=n;i<lim;i++)
            b[i]=0;
    }
    inline void Exp(int n,int *a,int *b){
        polyexp(n,a,b);
    }
}
using namespace Poly;
int ask[5],L;
inline int solve(int m){
    memset(g,0,sizeof(g));
    memset(tmp1,0,sizeof(tmp1));
    for(int i=0;i<L;i++)
        g[i]=1ll*(mod-m)*F[i]%mod;
    Exp(L,g,tmp1);
    init(L<<1);
    NTT(tmp1,1);
    for(int i=0;i<lim;i++)
        tmp1[i]=1ll*tmp1[i]*tmp2[i]%mod;
    NTT(tmp1,-1);
    return 1ll*tmp1[m-1]*inv[m]%mod*fac[m-1]%mod;
}
int main(){
    for(int i=0;i<5;i++)
        ask[i]=read(),n=max(n,ask[i]+1);
    init(n,0);
    L=lim;
    Prefix(L);
    for(int i=0;i<L;i++)
        f[i]=1ll*qpow(2,1ll*i*(i-1)/2%(mod-1))*ifac[i]%mod;
    Log(L,f,F);
    for(int i=0;i<L;i++)
        F[i]=1ll*F[i]*i%mod;
    Der(F,tmp2,L);
    NTT(tmp2,1);
    for(int i=0;i<5;i++)
        write(solve(ask[i])),putc('\n');
    flush();
    return 0;
}
posted @ 2021-07-28 20:13  ffffyc  阅读(14)  评论(0)    收藏  举报  来源