题目
https://www.luogu.com.cn/problem/P4841
思路
设
f
(
n
)
f(n)
f(n) 为
n
n
n 个点的简单有标号无向连通图数目,
g
(
n
)
g(n)
g(n) 为简单有标号无向图数目。那么显然有
g
(
n
)
=
2
C
n
2
=
∑
i
=
1
n
C
n
−
1
i
−
1
f
(
i
)
g
(
n
−
i
)
g(n)=2^{C_n^2}=\sum_{i=1}^nC_{n-1}^{i-1}f(i)g(n-i)
g(n)=2Cn2=i=1∑nCn−1i−1f(i)g(n−i)
把
C
n
−
1
i
−
1
C_{n-1}^{i-1}
Cn−1i−1 展开并用
2
C
i
2
2^{C_i^2}
2Ci2 代替
g
(
i
)
g(i)
g(i) 得
2
c
n
2
(
n
−
1
)
!
=
∑
i
=
1
n
f
(
i
)
(
i
−
1
)
!
g
(
n
−
i
)
(
n
−
i
)
!
\frac{2^{c_n^2}}{(n-1)!}=\sum_{i=1}^n\frac{f(i)}{(i-1)!}\frac{g(n-i)}{(n-i)!}
(n−1)!2cn2=i=1∑n(i−1)!f(i)(n−i)!g(n−i)
可以发现这是一个卷积
可以表示成
H
=
F
∗
G
H=F*G
H=F∗G
则
F
=
H
∗
G
−
1
F=H*G^{-1}
F=H∗G−1
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=(1<<19)+77,mod=1004535809;
const ll g=3;
int r[N];ll a0[N];
ll power(ll x,ll t)
{
ll b=1;
while(t)
{
if(t&1) b=b*x%mod; x=x*x%mod; t>>=1;
}
return b;
}
void dft(ll *a,int n,int f)
{
for(int i=1; i<=n; i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2; i<=n; i<<=1)
{
int now=i>>1; ll wn=power(g,(mod-1)/i);
if(f==-1) wn=power(wn,mod-2);
for(int j=0; j<n; j+=i)
{
ll x,y,w=1;
for(int k=j; k<j+now; k++,w=w*wn%mod)
{
x=a[k],y=w*a[k+now]%mod;
a[k]=(x+y)%mod,a[k+now]=(x-y+mod)%mod;
}
}
}
ll invn=power(n,mod-2);
if(f==-1) for(int i=0; i<n; i++) a[i]=a[i]*invn%mod;
}
void ginv(int n,ll *a,ll *b)
{
if(n==1)
{
b[0]=power(a[0],mod-2); return;
}
ginv(n>>1,a,b);
int len=1,lg=0;
while(len<n<<1) len<<=1,lg++;
for(int i=1; i<=len; i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));
for(int i=0; i<n; i++) a0[i]=a[i];
for(int i=n; i<len; i++) a0[i]=0;
dft(b,len,1); dft(a0,len,1);
for(int i=0; i<len; i++)
b[i]=b[i]*((2-a0[i]*b[i]%mod+mod)%mod)%mod;
dft(b,len,-1);
// for(int i=0; i<len; i++) b0[i]=0;
for(int i=n; i<len; i++) b[i]=0;
}
ll inv[N],unfac[N],c2[N],gg[N],h[N],f[N],G[N],ans;
int n;
void init(int n)
{
inv[1]=unfac[1]=unfac[0]=1;
for(int i=2; i<=n; i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod,unfac[i]=unfac[i-1]*inv[i]%mod;
c2[1]=1;
for(ll i=2; i<=n; i++) c2[i]=power(2,i*(i-1)/2%(mod-1));
gg[0]=1;
for(int i=1; i<=n; i++) gg[i]=unfac[i]*c2[i]%mod,h[i]=unfac[i-1]*c2[i]%mod;
}
int main()
{
scanf("%d",&n);
init(n);
int len=1,lg=0;
while(len<=n) len<<=1,lg++;
ginv(len,gg,G);
len<<=1; lg++;
for(int i=1; i<=len; i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));
dft(h,len,1); dft(G,len,1);
for(int i=0; i<len; i++) f[i]=h[i]*G[i]%mod;
dft(f,len,-1);
ll fac=1;
for(ll i=1; i<n; i++) fac=fac*i%mod;
ans=f[n]*fac%mod;
printf("%lld",ans);
}