刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.
仅一行一个整数, 为方案数 mod 1004535809.
我们定义$f[i]$为点数为$i$的无向连通图的数量,我们考虑已经计算出了前$n-1$个点的答案,考虑新加入第$n$号节点,这个$n$号节点一定是联通了之前的若干个联通块,所以我们枚举$1$号节点所在的联通块的大小$s$,那么$n$号节点和$1$号节点所在的联通块联通的方案有$2^s-1$种,这个联通块的方案为$f[s]$,剩下的$n-s$个点就是一个子问题了也就是$f[n-s]$,那么最后的式子就是:$\sum _{s=1}^{n-1} \textrm{C}_{n-2}^{s-1}f[n-s]f[s](2^s-1)$
发现这是一个分治$NTT$,然而复杂度貌似是$O(Nlog^2N)$的...
定义$f[i]$代表点数为$i$的无向联通图的数量,考虑总的可能出现在图中的边有$\textrm{C}_{n}^{2}$种,那么生成图的数量就是$2^{\textrm{C}_{n}^{2}}$,现在我们考虑不合法的方案:依旧考虑$1$号节点所在的联通块大小为$s$,那么其他的$n-s$个点的子图随便排列,也就是说,不合法的为$\sum _{j=1}^{i-1}f[j]\textrm{C}_{i-1}^{j-1}2^{\textrm{C}_{i-j}^{2}}$...
$\frac{ f[i] }{ (i-1)! }=\frac{ 2^{\textrm{C}_{i}^{2}} }{ (i-1)! }-\frac{\sum _{j=1}^{i-1}f[j]\textrm{C}_{i-1}^{j-1}2^{\textrm{C}_{i-j}^{2}}}{(i-1)!}$
$\sum_{j=1}^{i}\frac{f[j]}{(j-1)!}*\frac{ 2^{ \textrm{C}_{i-j}^{2} } }{(i-j)!}=\frac{2^{\textrm{C}_{i}^{2}}}{(i-1)!}$
那么$A*B=C$,我们可以得出$A=C*B^{-1}$,所以求个逆$NTT$一下就好了...
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=1000000+5,mod=1004535809,G=3;
int n,m,L,N,R[maxn],a[maxn],b[maxn],c[maxn],d[maxn],fac[maxn],inv[maxn];
inline int power(int x,long long y){
int res=1;
while(y){
if(y&1) res=1LL*res*x%mod;
x=1LL*x*x%mod,y>>=1;
}
return res;
}
inline void NTT(int *a,int f,int n,int L){
for(int i=0;i<n;i++)
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
for(int i=0;i<n;i++)
if(i<R[i]) swap(a[i],a[R[i]]);
for(int i=1;i<n;i<<=1){
int wn=power(G,(mod-1)/(i<<1));
if(f==-1) wn=power(wn,mod-2);
for(int j=0;j<n;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=1LL*w*wn%mod){
int x=a[j+k],y=1LL*a[j+k+i]*w%mod;
a[j+k]=(x+y)%mod;
a[j+k+i]=(x-y+mod)%mod;
}
}
}
if(f==-1){
int tmp=power(n,mod-2);
for(int i=0;i<n;i++)
a[i]=1LL*a[i]*tmp%mod;
}
}
inline void inverse(int *a,int *b,int n,int L){
if(n==1){
b[0]=power(a[0],mod-2);return;
}
inverse(a,b,n>>1,L-1);
memcpy(d,a,n*sizeof(int));
memset(d+n,0,n*sizeof(int));
NTT(d,1,n<<1,L+1);NTT(b,1,n<<1,L+1);
for(int i=0;i<n<<1;i++) b[i]=1LL*b[i]*((2-1LL*d[i]*b[i]%mod+mod)%mod)%mod;
NTT(b,-1,n<<1,L+1);
memset(b+n,0,n*sizeof(int));
}
signed main(void){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
scanf("%d",&n);fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mod;
inv[n]=power(fac[n],mod-2);
for(int i=n-1;i>=0;i--) inv[i]=1LL*inv[i+1]*(i+1)%mod;
m=n<<1;for(N=1;N<=m;N<<=1) L++;a[0]=1;
for(int i=1;i<=n;i++) a[i]=1LL*power(2,1LL*i*(i-1)/2)*inv[i]%mod;
for(int i=1;i<=n;i++) c[i]=1LL*power(2,1LL*i*(i-1)/2)*inv[i-1]%mod;
inverse(a,b,N,L);
NTT(b,1,N,L),NTT(c,1,N,L);
for(int i=0;i<N;i++) b[i]=1LL*b[i]*c[i]%mod;
NTT(b,-1,N,L);
printf("%d\n",(int)(1LL*b[n]*fac[n-1]%mod));
return 0;
}