题目链接
推一波式子
首先如果不要求联通的话公式很简单,令n个点不要求联通的方案数为
g
n
g_n
gn
g
n
=
2
n
∗
(
n
−
1
)
2
g_n=2^{\frac{n*(n-1)}{2}}
gn=22n∗(n−1)
因为每条边都可以选或不选
然后假设要求联通的方案数为
f
n
f_n
fn
可以找出
g
n
g_n
gn与
f
f
f的关系
g
n
=
∑
i
=
1
n
(
n
−
1
i
−
1
)
f
i
g
n
−
i
g_n=\sum_{i=1}^n {n-1\choose i-1} f_ig_{n-i}
gn=i=1∑n(i−1n−1)fign−i
相当于枚举第一个点所在的联通块大小为i,然后乘以其它点随便连的方案数,如果不理解请再看一下g和f的定义
现在我们要求
f
n
f_n
fn所以拆一下式子
g
n
=
f
n
+
∑
i
=
1
n
−
1
(
n
−
1
i
−
1
)
f
i
g
n
−
i
g_n=f_n+\sum_{i=1}^{n-1} {n-1\choose i-1} f_ig_{n-i}
gn=fn+i=1∑n−1(i−1n−1)fign−i
f
n
=
g
n
−
∑
i
=
1
n
−
1
(
n
−
1
i
−
1
)
f
i
g
n
−
i
f_n=g_n-\sum_{i=1}^{n-1} {n-1\choose i-1} f_ig_{n-i}
fn=gn−i=1∑n−1(i−1n−1)fign−i
f
n
=
g
n
−
∑
i
=
1
n
−
1
(
n
−
1
)
!
(
i
−
1
)
!
(
n
−
i
)
!
f
i
g
n
−
i
f_n=g_n-\sum_{i=1}^{n-1} \frac{(n-1)!}{(i-1)!(n-i)!} f_ig_{n-i}
fn=gn−i=1∑n−1(i−1)!(n−i)!(n−1)!fign−i
f
n
=
g
n
−
(
n
−
1
)
!
∑
i
=
1
n
−
1
f
i
(
i
−
1
)
!
g
n
−
i
(
n
−
i
)
!
f_n=g_n-(n-1)!\sum_{i=1}^{n-1} \frac{f_i}{(i-1)!} \frac{g_{n-i}}{(n-i)!}
fn=gn−(n−1)!i=1∑n−1(i−1)!fi(n−i)!gn−i
后面这个式子看着像卷积
∑
i
=
1
n
−
1
f
i
(
i
−
1
)
!
g
n
−
i
(
n
−
i
)
!
\sum_{i=1}^{n-1} \frac{f_i}{(i-1)!} \frac{g_{n-i}}{(n-i)!}
i=1∑n−1(i−1)!fi(n−i)!gn−i
令
h
i
=
f
i
(
i
−
1
)
!
h_i=\frac{f_i}{(i-1)!}
hi=(i−1)!fi
t
i
=
g
i
i
!
t_i=\frac{g_i}{i!}
ti=i!gi代入得
(
n
−
1
)
!
h
n
=
n
!
t
n
−
(
n
−
1
)
!
∑
i
=
1
n
−
1
h
i
t
n
−
i
(n-1)!h_n=n!t_n-(n-1)!\sum_{i=1}^{n-1} h_i t_{n-i}
(n−1)!hn=n!tn−(n−1)!i=1∑n−1hitn−i
h
n
=
n
t
n
−
∑
i
=
1
n
−
1
h
i
t
n
−
i
h_n=nt_n-\sum_{i=1}^{n-1} h_i t_{n-i}
hn=ntn−i=1∑n−1hitn−i
然后分治FFT就完事了
顺便一提,这题的原根也是3
代码如下:
#include<bits/stdc++.h>
#define mod 1004535809
#define gg 3
using namespace std;
int r[400010];
long long tmp1[400010],tmp2[400010],h[400010],t[400010];
long long fac[400010],inv[400010];
long long kasumi(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void NTT(long long *a,int kd,int logn)
{
int lim=(1<<logn);
for(int i=0;i<lim;i++)
{
r[i]=(r[i>>1]>>1)|((i&1)<<(logn-1));
}
for(int i=0;i<lim;i++)
{
if(i<r[i]) swap(a[i],a[r[i]]);
}
for(int mid=1;mid<lim;mid<<=1)
{
long long wn=kasumi(gg,(mod-1)/(mid<<1));
if(kd) wn=kasumi(wn,mod-2);
for(int i=0;i<lim;i+=(mid<<1))
{
long long w=1;
for(int j=0;j<mid;j++,w=w*wn%mod)
{
long long x=a[i+j];
long long y=a[i+j+mid]*w%mod;
a[i+j]=(x+y)%mod;
a[i+j+mid]=(x-y+mod)%mod;
}
}
}
if(kd)
{
int invl=kasumi(lim,mod-2);
for(int i=0;i<lim;i++)
{
a[i]=a[i]*invl%mod;
}
}
}
void solve(int l,int r,int logn)
{
if(!logn) return ;
int mid=(l+r)>>1;
solve(l,mid,logn-1);
for(int i=l;i<=r;i++)
{
tmp2[i-l]=t[i-l];
}
for(int i=l;i<=mid;i++)
{
tmp1[i-l]=h[i];
}
for(int i=mid+1;i<=r;i++)
{
tmp1[i-l]=0;
}
NTT(tmp1,0,logn);
NTT(tmp2,0,logn);
for(int i=l;i<=r;i++)
{
tmp1[i-l]=tmp1[i-l]*tmp2[i-l]%mod;
}
NTT(tmp1,1,logn);
for(int i=mid+1;i<=r;i++)
{
h[i]=(h[i]-tmp1[i-l]+mod)%mod;
}
solve(mid+1,r,logn-1);
}
void init()
{
fac[0]=1;
for(int i=1;i<=200000;i++)
{
fac[i]=fac[i-1]*i%mod;
}
inv[200000]=kasumi(fac[200000],mod-2);
for(int i=199999;i>=0;i--)
{
inv[i]=inv[i+1]*(i+1)%mod;
}
t[0]=1;
long long tmp;
for(int i=1;i<=200000;i++)
{
tmp=kasumi(2,1ll*(i-1)*i/2);
t[i]=tmp*inv[i]%mod;
h[i]=t[i]*i%mod;
}
}
int n;
int main()
{
int cnt=1;
init();
scanf("%d",&n);
for(;(1<<cnt)<=n;cnt++);
solve(0,(1<<cnt)-1,cnt);
printf("%lld\n",h[n]*fac[n-1]%mod);
}