邊雙連通圖計數

題目

F(x)=2(i2)xii!F(x)=\sum \frac {2^{\binom i2}x^i}{i!}是無向圖個數的指數生成函數。
D(x)=(lnF(x))xD(x)=(\ln F(x))'x是有根無向連通圖的指數生成函數。(注意[x0]D(x)=0[x^0]D(x)=0因爲沒有根)
B(x)B(x)是有根邊雙連通圖的指數生成函數。
D(x)D(x)中枚舉根的邊雙聯通分量大小可以得到方程:
D(x)=i=1bixiexp(iD(x))i!D(x) = \sum_{i=1} \frac {b_ix^i\exp(iD(x))}{i!}
後面那個exp\exp其實就是在把圖中其他有根無向連通圖連到根的邊雙聯通分量上的一個點,並且分配標號。
所以
D(x)=i=1bixiexp(D(x))ii!=i=1bi(xexp(D(x)))ii!=B(xexpD(x))\begin{aligned} D(x) &= \sum_{i=1} \frac {b_i x^i \exp(D(x))^i}{i!}\\&=\sum_{i=1} \frac {b_i (x\exp(D(x)))^i}{i!}\\&= B(x \exp D(x)) \end{aligned}
F(x)=xexpD(x),G(F(x))=xF(x) = x \exp D(x) , G(F(x)) = x
所以可以得到
D(G(x))=B(G(F(x)))=B(x)D(G(x)) = B(G(F(x))) = B(x)

那麼根據擴展拉格朗日反演可以得到:
[xn]B(x)=[xn]D(G(x))=[xn1]D(x)xnnF(x)n=[xn1]D(x)n×(xF(x))n=[xn1]D(x)nexp(nlnF(x)x)=[xn1]D(x)exp(nD(x))n[x^n]B(x) = [x^n]D(G(x)) = [x^{n-1}] \frac {D(x)'x^n}{nF(x)^n}=[x^{n-1}] \frac{D(x)'}n \times (\frac {x}{F(x)})^n\\ = [x^{n-1}] \frac {D(x)'}n\exp(-n \ln \frac {F(x)}x) = [x^{n-1}]\frac {D(x)'\exp(-nD(x))}n

#include<bits/stdc++.h>
#define maxn 600005
#define mod 998244353
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int Wl,Wl2,w[maxn]={1},lg[maxn],inv[maxn]={1,1},fac[maxn]={1,1},invf[maxn]={1,1};
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod; return r; }
void init(int n){
	for(Wl=1;n>=Wl<<1;Wl<<=1); w[1]=Pow(3,(mod-1)/(Wl2=Wl<<1));
	rep(i,2,Wl2) w[i]=1ll*w[i-1]*w[1]%mod,lg[i]=lg[i>>1]+1,fac[i]=1ll*fac[i-1]*i%mod,
		inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod,invf[i]=1ll*invf[i-1]*inv[i]%mod;
}
void NTT(int *A,int n,int tp){
	static int r[maxn];
	rep(i,1,n-1) i<(r[i]=r[i>>1]>>1|(i&1)<<lg[n]-1) && (swap(A[i],A[r[i]]),0);
	for(int L=1,B=Wl;L<n;L<<=1,B>>=1) for(int s=0;s<n;s+=L<<1) for(int k=s,x=0,t;k<s+L;k++,x+=B)
		t=1ll*w[tp^1?Wl2-x:x]*A[k+L]%mod,A[k+L]=(A[k]-t)%mod,A[k]=(A[k]+t)%mod;
	if(tp^1) rep(i,0,n-1) A[i]=1ll*A[i]*inv[n]%mod;
}
void Inv(int *A,int *B,int n){
	B[B[1]=0]=Pow(A[0],mod-2);
	static int t[maxn];
	for(int k=2,L=4;k<(n<<1);k<<=1,L<<=1){
		rep(i,0,L-1) t[i]=i<k?A[i]:B[i]=0;
		NTT(t,L,1),NTT(B,L,1);
		rep(i,0,L-1) B[i]=B[i]*(2-1ll*t[i]*B[i]%mod)%mod;
		NTT(B,L,-1);
		rep(i,min(n,k),L-1) B[i] = 0;
	}
}
void Ln(int *A,int *B,int n){
	static int t[maxn];
	int L = 1 << lg[2*n-2] + 1;
	Inv(A,B,n);
	rep(i,0,L-1) t[i] = i < n-1 ? A[i+1] * (i+1ll) % mod : B[i] = 0;
	NTT(t,L,1),NTT(B,L,1);
	rep(i,0,L-1) t[i] = 1ll * t[i] * B[i] % mod;
	NTT(t,L,-1);
	B[0] = 0;
	rep(i,1,L-1) B[i] = i < n ? 1ll * t[i-1] * inv[i] % mod : 0; 
}
void Exp(int *A,int *B,int n){
	B[B[1] = 0] = 1;
	static int t[maxn];
	for(int k=2,L=4;k<(n<<1);k<<=1,L<<=1){
		Ln(B,t,k);
		rep(i,0,L-1) t[i] = i < k ? ((i == 0) + A[i] - t[i]) % mod : B[i] = 0;
		NTT(t,L,1),NTT(B,L,1);
		rep(i,0,L-1) B[i] = 1ll * t[i] * B[i] % mod;
		NTT(B,L,-1);
		rep(i,min(n,k),L-1) B[i] = 0;
	} 
}

int F[maxn],D[maxn],B[maxn],C[maxn],E[maxn],G[maxn];
int main(){
	init(200000);
	for(int i=0;i<=100000;i++) F[i] = 1ll * Pow(2 , (i * (i-1ll) / 2) % (mod - 1)) * invf[i] % mod;
	Ln(F,D,100001);
	for(int i=0;i<=100000;i++) D[i] = 1ll * D[i] * i % mod;
	for(int i=0;i<100000;i++) E[i] = 1ll * D[i+1] * (i+1) % mod;
	for(int T=5,n;T--;){
		scanf("%d",&n);
		for(int j=0;j<n;j++)
			C[j] = j < n ? (-1ll * D[j] * n) % mod : 0;
		Exp(C,G,n);
		int ans = 0;
		for(int i=0;i<n;i++)
			ans = (ans + 1ll * G[i] * E[n-1-i]) % mod;
		ans = (1ll * ans * fac[n-1] % mod * inv[n] % mod + mod) % mod;
		printf("%d\n",ans);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章