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

题目描述

给定 \(n\),求 \(n\) 个点的简单有标号无向连通图数目,对 \(1004535809\) 取模。

数据范围:\(n\le130000\)

时间限制:\(2000\operatorname{ms}\)

Solution

\(f_i\) 表示 \(i\) 个点的简单有标号无向连通图数目,\(g_i\) 表示 \(i\) 个点的简单有标号无向图的数目,有 \(g_i=2^{\binom{n}{2}}\)

枚举一号节点所在环大小,把这个环孤立起来,统计方案数,有

\[g_n=\sum_{i=1}^{n}{\dbinom{n-1}{i-1}f_ig_{n-i}} \]

把组合数展开,有

\[g_n=\sum_{i=1}^{n}{\frac{(n-1)!}{(i-1)!(n-i)!}}f_ig_{n-i} \]

\[\frac{g_n}{(n-1)!}=\sum_{i=1}^{n}\frac{f_i}{(i-1)!}\times\frac{g_{n-i}}{(n-i)!} \]

\(F(x)=\sum_{i=1}^{n}\frac{f_i}{(i-1)!}x^i\)\(G(x)=\sum_{i=0}^{n}{\frac{g_i}{i!}x^i}\)\(H(x)=\sum_{i=1}^{n}{\frac{g_i}{(i-1)!}x^i}\)
那么有

\[H(x)=F(x)G(x)\bmod{x^{n+1}} \]

所以

\[F(x)=H(x)G^{-1}(x)\bmod{x^{n+1}} \]

多项式求逆即可解决,时间复杂度为 \(O(n\log n)\)

Code

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=300000,MLY=1004535809,g=3;
int bit,tot,rev[maxn];
int G[maxn],invG[maxn],H[maxn],g2[maxn];
int fac[maxn],invfac[maxn],n;
inline int power(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%MLY;
		a=1ll*a*a%MLY;
		b>>=1;
	}
	return ans;
}
inline void Init(int n){
	bit=0;while((1<<bit)<=(n<<1))++bit;
	tot=1<<bit;
	for(int i=1;i<tot;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
inline void NTT(int *a,int inv){
	for(int i=0;i<tot;++i)
		if(i<rev[i])
			swap(a[i],a[rev[i]]);
	for(int mid=1;mid<tot;mid<<=1){
		int tmp=power(g,(MLY-1)/(mid<<1));
		if(!~inv)tmp=power(tmp,MLY-2);
		for(int i=0;i<tot;i+=(mid<<1)){
			for(int j=0,w=1;j<mid;++j,w=1ll*w*tmp%MLY){
				int x=a[i+j],y=1ll*w*a[i+j+mid]%MLY;
				a[i+j]=(x+y)%MLY;a[i+j+mid]=(x-y+MLY)%MLY;
			}
		}
	}
	if(!~inv){
		inv=power(tot,MLY-2);
		for(int i=0;i<tot;++i)a[i]=1ll*a[i]*inv%MLY;
	}
}
inline void PolyMul(int *F,int *G,int n,int inv=0){
	static int a[maxn],b[maxn];
	Init(n);
	for(int i=0;i<n;++i)a[i]=F[i],b[i]=G[i];
	for(int i=n;i<tot;++i)a[i]=b[i]=0;
	NTT(a,1);NTT(b,1);
	for(int i=0;i<tot;++i){
		if(inv)a[i]=b[i]*(2-1ll*a[i]*b[i]%MLY+MLY)%MLY;
		else a[i]=1ll*a[i]*b[i]%MLY;
	}
	NTT(a,-1);
	for(int i=0;i<n;++i)G[i]=a[i];
}
inline void PolyInv(int *F,int *G,int n){
	if(n==1){
		G[0]=power(F[0],MLY-2);
		return;
	}
	PolyInv(F,G,(n+1)>>1);
	PolyMul(F,G,n,1);
}
int main(){
	scanf("%d",&n);
	fac[0]=invfac[0]=1;
	for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*i%MLY;
	invfac[n]=power(fac[n],MLY-2);
	for(int i=n-1;i;--i)invfac[i]=invfac[i+1]*(i+1ll)%MLY;
	for(int i=0;i<=n;++i)g2[i]=power(2,i*(i-1ll)/2%(MLY-1));
	for(int i=1;i<=n;++i)H[i]=1ll*g2[i]*invfac[i-1]%MLY;
	for(int i=0;i<=n;++i)G[i]=1ll*g2[i]*invfac[i]%MLY;
	PolyInv(G,invG,n+1);
	PolyMul(H,invG,n+1);
	printf("%lld",1ll*invG[n]*fac[n-1]%MLY);
	return 0;
}
posted @ 2021-04-28 12:38  7103  阅读(89)  评论(0)    收藏  举报