指数生成函数(EGF)

熟知指数生成函数(以下简称为EGF)定义为:

[F(x)=sumlimits_{n=0}^inftydfrac{a_n}{n!}x^n ]

并且两个EGF相乘为 (F(x)G(x)) 是数列 (left{sumlimits^n_{k=0}dbinom{n}{k}a^kb^{n-k} ight}_{n=0}^infty) 的EGF

因为我们将 ( ext{e}^x) 再原点处进行泰勒展开得到了数列 ({1,1,cdots}_{n=0}^infty) 的无穷级数形式

所以如果一个数列为 ({1,1,cdots}_{n=0}^infty) 那么它EGF的封闭形式为 ( ext{e}^x)


一个EGF (F(x)=sumlimits_{n=0}^inftydfrac{a_n}{n!}x^n) 同时也是数列 (left{dfrac{a_n}{n!} ight}_{n=0}^infty) 的OGF

我们考虑一个长度为 (n) 数列的排列数(数列中的数互不相同)

显而易见,排列数是 (n!)

写成EGF的形式也就是

[F(x)=sumlimits_{n=0}^inftydfrac{n!}{n!}x_n=dfrac{1}{1-x} ]

那么我们再考虑一个长度为 (n) 的数列的圆排列数

显然对于每个排列,我们将其旋转 (n) 次的到的圆排列相同

显然,圆排列数是 ((n-1)!)

写成EGF的形式:

[egin{align*} G(x)&=sumlimits_{n=1}^inftydfrac{(n-1)!}{n!}x_n \ &=sumlimits_{n=1}^inftydfrac{x_n}{n} \ &=lnleft(dfrac{1}{1-x} ight) end{align*} ]

是不是发现了显然可以 (exp)

(exp G(x)=F(x))

在学习群论的时候,我们知道每个置换 (ain S_n) 或是一个循环置换,或是若干个不相交的循环置换的乘积

此时我们把每个排列看成一个置换

长度为 (n) 的排列数方案数即是把其分成 (k) 个集合,然后每个集合的圆排列的方案数的积


P4841 [集训队作业2013]城市规划

熟知 (n) 个点的有标号无向图的个数是 (2^inom{n}{2})

每个无向图可以看作若干个集合构成,每个集合里的元素同属一个连通图

(n) 个点的有标号无向图的EGF是 (F(x))(n) 个点的有标号无向连通图的EGF是 (G(x))

此时我们很容易仿照上文得到 (exp G(x)=F(x)),即 (G(x)=ln F(x))

直接多项式 (ln) 即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 1000001
#define INF 1100000000
#define Kafuu return
#define Chino 0
#define fx(l,n) inline l n
#define set(l,n,ty,len) memset(l,n,sizeof(ty)*len)
#define cpy(f,t,ty,len) memcpy(t,f,sizeof(ty)*len)
#define R register int
#define C const
#define int long long
using namespace std;
C int mod=1004535809,pr=3;
int n,br[N],ppr[N],x=1,invp,invx,A[N],B[N],fc[N];
fx(int,gi)(){
	char c=getchar();int s=0,f=1;
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') s=(s<<3)+(s<<1)+(c-'0'),c=getchar();
	return s*f;
}
fx(int,pow)(int a,int b=mod-2){
	int ans=1;
	while(b){
		if(b&1) (ans*=a)%=mod;
		(a*=a)%=mod;
		b>>=1;
	}
	return ans;
}
fx(void,NTT)(int *f,C short r,C int x){
	R len,hl,exp,uni,s,i;
	for(i=0;i<x;i++) br[i]=(br[i>>1]>>1)|((i&1)?x>>1:0);
	for(i=0;i<x;i++) if(i<br[i]) swap(f[i],f[br[i]]);
	for(len=2,hl=1;len<=x;hl=len,len<<=1){
		exp=pow(r==1?pr:invp,(mod-1)/len);
		for(i=1;i<hl;i++) ppr[i]=ppr[i-1]*exp%mod;
		for(s=0;s<x;s+=len){
			for(i=0;i<hl;i++){
				uni=ppr[i]*f[i|s|hl]%mod;
				f[i|s|hl]=(f[i|s]-uni+mod)%mod;
				f[i|s]=(f[i|s]+uni)%mod;
			}
		}
	}
	if(r==-1){
		invx=pow(x);
		for(i=0;i<x;i++) (f[i]*=invx)%=mod;
	}
}
fx(void,INV)(int *f,const int x){
	static int le[N],ri[N],inv[N];
	inv[0]=pow(f[0]);
	for(R len=2,hl=1,o;len<=x;hl=len,len<<=1){
		for(o=0;o<hl;o++) le[o]=(inv[o]<<1)%mod;
		cpy(f,ri,int,len);
		NTT(inv,1,len<<1);NTT(ri,1,len<<1);
		for(o=0;o<(len<<1);o++) (((inv[o]*=inv[o])%=mod)*=ri[o])%=mod;
		NTT(inv,-1,len<<1);
		for(o=0;o<len;o++) inv[o]=(le[o]-inv[o]+mod)%mod;
		set(inv+len,0,int,len);
	}
	cpy(inv,f,int,n);
}
fx(void,DER)(int *f,C int len){
	for(int i=1;i<len;i++) f[i-1]=f[i]*i%mod;
	f[len-1]=0;
}
fx(void,INT)(int *f,C int len){
	for(R i=len-1;i>=1;i--) f[i]=f[i-1]*pow(i)%mod;
	f[0]=0;
}
signed main(){
	ios::sync_with_stdio(0);
	n=gi();
	n+=1;fc[0]=1;
	for(R i=1;i<n;i++) fc[i]=fc[i-1]*i%mod;
	for(R i=0;i<n;i++) A[i]=pow(2,i*(i-1)/2)*pow(fc[i])%mod;
	cpy(A,B,int,n);
	while(x<n) x<<=1;
	invp=pow(pr);ppr[0]=1;
	INV(A,x);DER(B,n);
	while(x<n+n) x<<=1;
	NTT(A,1,x);NTT(B,1,x);
	for(R i=0;i<x;i++) (A[i]*=B[i])%=mod;
	NTT(A,-1,x);INT(A,n);
	printf("%lld",A[n-1]*fc[n-1]%mod);
}
原文地址:https://www.cnblogs.com/zythonc/p/14452315.html