点\边双连通图计数

文章目录

题目

点双
边双

点双

一个点可以属于多个点双
记有根无向连通图的指数型生成函数为 D ( x ) D(x) ,有根点双的指数型生成函数为 B ( x ) B(x)
注意 d 0 = 0 d_0=0 ,因为有根
考虑包含根的一个点双
在这里插入图片描述
这个点双内的每个点都可以向外连出一个无向连通图,但是不能连回来(否则也属于这个点双)
为什么不用考虑根连出去的无向图
其实是定义的问题,因为两个点也算作一个点双
也就是 i = 1 b i + 1 D i ( x ) i ! \sum_{i=1}^\infty b_{i+1}\frac{D^i(x)}{i!}
为什么要除以 i i! 因为 b i + 1 b_{i+1} 本身已经让 i + 1 i+1 个点方案有序,那么之后乘 n ! n! 就可以视作重排列(这 i i 个点颜色一样)
然后直接来
D ( x ) = x e i = 1 b i + 1 D i ( x ) i ! D(x)=xe^{\sum_{i=1}^\infty b_{i+1}\frac{D^i(x)}{i!}}
那么就是 D ( x ) = x × e x p   B ( D ( x ) ) D(x)=x\times exp\ B'(D(x))
现在要求 B ( x ) B'(x)
变形得到
l n D ( x ) x = B ( D ( x ) ) ln\frac{D(x)}{x}=B'(D(x))
G ( x ) = l n D ( x ) x G(x)=ln\frac{D(x)}{x}
那么
B ( D ( x ) ) = G ( x ) B'(D(x))=G(x)

拉格朗日反演有拓展形式当 F ( G ( x ) ) = H ( x ) F(G(x))=H(x) 时候,有:
[ x n ] F ( x ) = 1 n [ x n 1 ] H ( x ) ( x G ( x ) ) n [x^n]F(x)=\frac{1}{n}[x^{n-1}]H'(x)(\frac{x}{G(x)})^n

[ x n ] B ( x ) = 1 n [ x n 1 ] G ( x ) ( x D ( x ) ) n [x^n]B'(x)=\frac{1}{n}[x^{n-1}]G'(x)(\frac{x}{D(x)})^n

算就行了
但是我们要取第 n 1 n-1 项,因为求了导,而且还是有根的
也就是 b n 2 n ! / n b_{n-2}*n!/n
n = 1 n=1 特判

边双

一个点可以属于一个边双
记有根无向连通图的指数型生成函数为 D ( x ) D(x) ,有根边双的指数型生成函数为 B ( x ) B(x)
注意 d 0 = 0 d_0=0 ,因为有根
考虑包含根的边双:
在这里插入图片描述
枚举边双大小后连接一个连通图,也就是 i D ( x ) iD(x)
可以想象成球上插羽毛
D ( x ) = i = 1 + b i e i D ( x ) i ! x i D(x)=\sum_{i=1}^{+\infty}b_i\frac{e^{iD(x)}}{i!}x^i
此时不用再乘 x x 了,因为已经枚举了根的 x x
也就是 D ( x ) = B ( e D ( x ) ) D(x)=B(e^{D(x)})
拉格朗日反演有拓展形式当 F ( G ( x ) ) = H ( x ) F(G(x))=H(x) 时候,有:
[ x n ] F ( x ) = 1 n [ x n 1 ] H ( x ) ( x G ( x ) ) n [x^n]F(x)=\frac{1}{n}[x^{n-1}]H'(x)(\frac{x}{G(x)})^n

[ x n ] B ( x ) = 1 n [ x n 1 ] D ( x ) ( x e D ( x ) ) n [x^n]B(x)=\frac{1}{n}[x^{n-1}]D'(x)(\frac{x}{e^{D(x)}})^n
求完以后:
b n n ! / n b_n*n!/n

代码

#pragma GCC optimize(2)
#include<set>    
#include<map>    
#include<stack>    
#include<ctime>    
#include<cstdio>    
#include<queue>    
#include<cmath>    
#include<vector>    
#include<cstring>   
#include<climits>    
#include<iostream>   
#include<algorithm>
using namespace std;
#define LL long long
inline int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f*x;
}
#define MAXN int(4e5)
#define INF 0x3f3f3f3f
const int Mod=998244353,g=3,rg=332748118;
inline int Mul(register LL x,register int y){
	x*=y;
	return x>=Mod?x%Mod:x;
}
inline int Add(register int x,register int y){
	x+=y;
	return x>=Mod?x-Mod:x;
}
inline int Pow(register int x,register LL y){
	register int ret=1;
	while(y){
		if(y&1) ret=Mul(ret,x);
		x=Mul(x,x),y>>=1;
	}
	return ret;
}
int rev[MAXN+5];
int pg[MAXN+5],prg[MAXN+5];
int fac[MAXN+5],ifac[MAXN+5],inv[MAXN+5];
	inline int Len(register int n){
		register int len,lg2;
		for(len=1,lg2=0;len<n;len<<=1)
			lg2++;
		for(register int i=1;i<=len;i++)
			rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg2-1));
		return len;
	}
	inline void NTT(int *A,int len,register int sign){
		for(register int i=0;i<len;i++)
			if(i<rev[i]) swap(A[i],A[rev[i]]);
		for(register int k=1;k<len;k<<=1){
			register int w0=(sign==1?pg[k]:prg[k]);
			for(register int j=0,siz=k<<1;j<len;j+=siz)
				for(register int i=0,w=1;i<k;i++,w=Mul(w,w0)){
					register int x=A[i+j],y=Mul(w,A[i+j+k]);
					A[i+j]=Add(x,y),A[i+j+k]=Add(x,Mod-y);
				}
		}
		if(sign==-1){
			register int Inv=Pow(len,Mod-2);
			for(register int i=0;i<len;i++)
				A[i]=Mul(A[i],Inv);
		}
		return ;
	}
	int tmp1[MAXN+5],tmp2[MAXN+5];
	inline void Poly_Mul(register int *A,register int*B,register int*C,register int n,register int m){//A,B,C均可不清空
		copy(A,A+n,tmp1),copy(B,B+m,tmp2);
		register int len=Len(n+m-1);
		fill(tmp1+n,tmp1+len,0),fill(tmp2+m,tmp2+len,0);
		NTT(tmp1,len,1),NTT(tmp2,len,1);
		for(int i=0;i<len;i++)
			C[i]=Mul(tmp1[i],tmp2[i]);
		NTT(C,len,-1);
		return ;
	}
	int tmp3[MAXN+5];
	inline void Poly_Inv(int *A,int *B,register int n){//B要清空
		if(n==1){
			B[0]=Pow(A[0],Mod-2);
			return ;
		}
		Poly_Inv(A,B,(n+1)/2);
		register int len=Len(2*n);
		copy(A,A+n,tmp3);
		fill(tmp3+n,tmp3+len,0),fill(B+n,B+len,0);
		NTT(tmp3,len,1),NTT(B,len,1);
		for(int i=0;i<len;i++)
			B[i]=1ll*(2+Mod-1ll*B[i]*tmp3[i]%Mod)%Mod*B[i]%Mod;
		NTT(B,len,-1),fill(B+n,B+len,0);
		return ;
	}
	inline void Poly_Deriv(int *A,int *B,register int n){
		for(register int i=1;i<n;i++)
			B[i-1]=Mul(A[i],i);
		B[n-1]=0;
		return ;
	}
	inline void Poly_Inter(int *A,int *B,register int n){//有取模
		for(register int i=n-1;i>=1;i--)
			B[i]=Mul(A[i-1],inv[i]);
		B[0]=0;
		return ;
	}
	int inva[MAXN+5],da[MAXN+5];
	inline void Poly_Ln(int *A,int *B,register int n){
		Poly_Inv(A,inva,n);
		Poly_Deriv(A,da,n);
		Poly_Mul(inva,da,B,n,n);
		Poly_Inter(B,B,n);
		return ;
	}
	int cF[MAXN+5];
	inline void Poly_Exp(int *A,int *B,int n){
		if(n==1){
			B[0]=1;
			return ;
		}
		Poly_Exp(A,B,(n+1)/2),Poly_Ln(B,cF,n);
		cF[0]=(1+A[0]-cF[0]+Mod)%Mod;
		for(int i=1;i<n;i++)
			cF[i]=(A[i]-cF[i]+Mod)%Mod;
		int len=Len(2*n);
		fill(cF+n,cF+len,0),fill(B+n,B+len,0);
		NTT(cF,len,1),NTT(B,len,1);
		for(int i=0;i<len;i++)
			B[i]=1ll*B[i]*cF[i]%Mod;
		NTT(B,len,-1),fill(B+n,B+len,0);
		return ;
	}
	int lna[MAXN+5];
	inline void Poly_Pow(int *A,int *P,int k,int n){
		Poly_Ln(A,lna,n);
		for(int i=0;i<n;i++)
			lna[i]=1ll*lna[i]*k%Mod;
		Poly_Exp(lna,P,n);
		return ;
	}
void Print(int *A,int n){
	for(int i=0;i<n;i++)
		printf("%d ",A[i]);
	puts("");
	return ;
}
#define N 100003
int T[MAXN+5],F[MAXN+5],G[MAXN+5],f[MAXN+5],P[MAXN+5],Ans[MAXN+5];
int main(){
	fac[0]=1;
	for(register int k=1;k<MAXN;k<<=1)	
		pg[k]=Pow(g,(Mod-1)/(k<<1)),prg[k]=Pow(rg,(Mod-1)/(k<<1));
	for(register int i=1;i<=N;i++)
		fac[i]=1ll*fac[i-1]*i%Mod;
	ifac[N]=Pow(fac[N],Mod-2);
	for(register int i=N-1;i>=0;i--)
		ifac[i]=1ll*ifac[i+1]*(i+1)%Mod;
	inv[1]=1;
	for(register int i=2;i<=N;i++)
		inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
	for(int t=1;t<=5;t++){
		int n=read();
		//if(n==1){
		//	puts("1");
		//	continue;
		//}
		for(int i=0;i<n+3;i++)
			T[i]=1ll*Pow(2,1ll*i*(i-1)/2%(Mod-1))*ifac[i]%Mod;
		fill(F,F+n+3,0);
		fill(G,G+n+3,0);
		fill(f,f+n+3,0);
		fill(P,P+n+3,0);
		Poly_Ln(T,F,n+3);
		for(int i=0;i<=n+1;i++)
			F[i]=1ll*F[i+1]*(i+1)%Mod;
		F[n+2]=0;
		Poly_Ln(F,G,n+3);
		Poly_Deriv(G,G,n+3);
		Poly_Ln(F,f,n+3);
		for(int i=0;i<n+3;i++)
			f[i]=1ll*f[i]*(Mod-(n-1))%Mod;
		Poly_Exp(f,P,n+3);
		Poly_Mul(P,G,Ans,n+3,n+3);
		int ans=1ll*Ans[n-2]*inv[n-1]%Mod*fac[n-1]%Mod;
		printf("%d\n",ans);
	}
	return 0;
}
//
#pragma GCC optimize(2)
#include<set>    
#include<map>    
#include<stack>    
#include<ctime>    
#include<cstdio>    
#include<queue>    
#include<cmath>    
#include<vector>    
#include<cstring>   
#include<climits>    
#include<iostream>   
#include<algorithm>
using namespace std;
#define LL long long
inline int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f*x;
}
#define MAXN int(4e5)
#define INF 0x3f3f3f3f
const int Mod=998244353,g=3,rg=332748118;
inline int Mul(register LL x,register int y){
	x*=y;
	return x>=Mod?x%Mod:x;
}
inline int Add(register int x,register int y){
	x+=y;
	return x>=Mod?x-Mod:x;
}
inline int Pow(register int x,register LL y){
	register int ret=1;
	while(y){
		if(y&1) ret=Mul(ret,x);
		x=Mul(x,x),y>>=1;
	}
	return ret;
}
int rev[MAXN+5];
int pg[MAXN+5],prg[MAXN+5];
int fac[MAXN+5],ifac[MAXN+5],inv[MAXN+5];
	inline int Len(register int n){
		register int len,lg2;
		for(len=1,lg2=0;len<n;len<<=1)
			lg2++;
		for(register int i=1;i<=len;i++)
			rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg2-1));
		return len;
	}
	inline void NTT(int *A,int len,register int sign){
		for(register int i=0;i<len;i++)
			if(i<rev[i]) swap(A[i],A[rev[i]]);
		for(register int k=1;k<len;k<<=1){
			register int w0=(sign==1?pg[k]:prg[k]);
			for(register int j=0,siz=k<<1;j<len;j+=siz)
				for(register int i=0,w=1;i<k;i++,w=Mul(w,w0)){
					register int x=A[i+j],y=Mul(w,A[i+j+k]);
					A[i+j]=Add(x,y),A[i+j+k]=Add(x,Mod-y);
				}
		}
		if(sign==-1){
			register int Inv=Pow(len,Mod-2);
			for(register int i=0;i<len;i++)
				A[i]=Mul(A[i],Inv);
		}
		return ;
	}
	int tmp1[MAXN+5],tmp2[MAXN+5];
	inline void Poly_Mul(register int *A,register int*B,register int*C,register int n,register int m){//A,B,C均可不清空
		copy(A,A+n,tmp1),copy(B,B+m,tmp2);
		register int len=Len(n+m-1);
		fill(tmp1+n,tmp1+len,0),fill(tmp2+m,tmp2+len,0);
		NTT(tmp1,len,1),NTT(tmp2,len,1);
		for(int i=0;i<len;i++)
			C[i]=Mul(tmp1[i],tmp2[i]);
		NTT(C,len,-1);
		return ;
	}
	int tmp3[MAXN+5];
	inline void Poly_Inv(int *A,int *B,register int n){//B要清空
		if(n==1){
			B[0]=Pow(A[0],Mod-2);
			return ;
		}
		Poly_Inv(A,B,(n+1)/2);
		register int len=Len(2*n);
		copy(A,A+n,tmp3);
		fill(tmp3+n,tmp3+len,0),fill(B+n,B+len,0);
		NTT(tmp3,len,1),NTT(B,len,1);
		for(int i=0;i<len;i++)
			B[i]=1ll*(2+Mod-1ll*B[i]*tmp3[i]%Mod)%Mod*B[i]%Mod;
		NTT(B,len,-1),fill(B+n,B+len,0);
		return ;
	}
	inline void Poly_Deriv(int *A,int *B,register int n){
		for(register int i=1;i<n;i++)
			B[i-1]=Mul(A[i],i);
		B[n-1]=0;
		return ;
	}
	inline void Poly_Inter(int *A,int *B,register int n){//有取模
		for(register int i=n-1;i>=1;i--)
			B[i]=Mul(A[i-1],inv[i]);
		B[0]=0;
		return ;
	}
	int inva[MAXN+5],da[MAXN+5];
	inline void Poly_Ln(int *A,int *B,register int n){
		Poly_Inv(A,inva,n);
		Poly_Deriv(A,da,n);
		Poly_Mul(inva,da,B,n,n);
		Poly_Inter(B,B,n);
		return ;
	}
	int cF[MAXN+5];
	inline void Poly_Exp(int *A,int *B,int n){
		if(n==1){
			B[0]=1;
			return ;
		}
		Poly_Exp(A,B,(n+1)/2),Poly_Ln(B,cF,n);
		cF[0]=(1+A[0]-cF[0]+Mod)%Mod;
		for(int i=1;i<n;i++)
			cF[i]=(A[i]-cF[i]+Mod)%Mod;
		int len=Len(2*n);
		fill(cF+n,cF+len,0),fill(B+n,B+len,0);
		NTT(cF,len,1),NTT(B,len,1);
		for(int i=0;i<len;i++)
			B[i]=1ll*B[i]*cF[i]%Mod;
		NTT(B,len,-1),fill(B+n,B+len,0);
		return ;
	}
	int lna[MAXN+5];
	inline void Poly_Pow(int *A,int *P,int k,int n){
		Poly_Ln(A,lna,n);
		for(int i=0;i<n;i++)
			lna[i]=1ll*lna[i]*k%Mod;
		Poly_Exp(lna,P,n);
		return ;
	}
void Print(int *A,int n){
	for(int i=0;i<n;i++)
		printf("%lld ",1ll*A[i]*fac[i]%Mod);
	puts("");
	return ;
}
#define N 100003
int C[MAXN+5],D[MAXN+5],Ds[MAXN+5],F[MAXN+5],E[MAXN+5],G[MAXN+5];
//D[i]:大小为i的无向连通图
int main(){
	fac[0]=1;
	for(register int k=1;k<MAXN;k<<=1)	
		pg[k]=Pow(g,(Mod-1)/(k<<1)),prg[k]=Pow(rg,(Mod-1)/(k<<1));
	for(register int i=1;i<=N;i++)
		fac[i]=1ll*fac[i-1]*i%Mod;
	ifac[N]=Pow(fac[N],Mod-2);
	for(register int i=N-1;i>=0;i--)
		ifac[i]=1ll*ifac[i+1]*(i+1)%Mod;
	inv[1]=1;
	for(register int i=2;i<=N;i++)
		inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
	for(int t=1;t<=5;t++){
		int n=read();
		if(n==1){
			puts("1");
			continue;
		}
		fill(C,C+n+1,0);
		fill(E,E+n+1,0);
		fill(D,D+n+1,0);
		fill(Ds,Ds+n+1,0);
		for(int i=0;i<n+1;i++)
			C[i]=1ll*Pow(2,1ll*i*(i-1)/2%(Mod-1))*ifac[i]%Mod;
		Poly_Ln(C,D,n+1);
		for(int i=0;i<n+1;i++)
			D[i]=1ll*D[i]*i%Mod;
		for(int i=0;i<n+1;i++)
			F[i]=Mul(D[i],Mod-n);
		Poly_Exp(F,E,n+1);
			
		Poly_Deriv(D,Ds,n+1);
		Poly_Mul(Ds,E,G,n+1,n+1);
		int ans=1ll*G[n-1]*inv[n]%Mod*fac[n-1]%Mod;
		printf("%d\n",ans);
	}
	return 0;
}
//

猜你喜欢

转载自blog.csdn.net/qq_37555704/article/details/107230264