[集训队作业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;
}

浙公网安备 33010602011771号