3456: 城市规划
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 640 Solved: 352
[Submit][Status][Discuss]
Description
刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.
Input
仅一行一个整数n(<=130000)
Output
仅一行一个整数, 为方案数 mod 1004535809.
Sample Input
Sample Output
HINT
对于 100%的数据, n <= 130000
Source
分析:
有两种方法:
一种是直接计算方案数
一种是用总的方案数减去不合法的方案数
如果直接计算:
我们定义$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} extrm{C}_{n-2}^{s-1}f[n-s]f[s](2^s-1)$
发现这是一个分治$NTT$,然而复杂度貌似是$O(Nlog^2N)$的...
另一种计算补集的方法的复杂度就优秀了一点:
定义$f[i]$代表点数为$i$的无向联通图的数量,考虑总的可能出现在图中的边有$ extrm{C}_{n}^{2}$种,那么生成图的数量就是$2^{ extrm{C}_{n}^{2}}$,现在我们考虑不合法的方案:依旧考虑$1$号节点所在的联通块大小为$s$,那么其他的$n-s$个点的子图随便排列,也就是说,不合法的为$sum _{j=1}^{i-1}f[j] extrm{C}_{i-1}^{j-1}2^{ extrm{C}_{i-j}^{2}}$...
两边同时除以$(i-1)!$:
$frac{ f[i] }{ (i-1)! }=frac{ 2^{ extrm{C}_{i}^{2}} }{ (i-1)! }-frac{sum _{j=1}^{i-1}f[j] extrm{C}_{i-1}^{j-1}2^{ extrm{C}_{i-j}^{2}}}{(i-1)!}$
最后的式子长成酱紫:
$sum_{j=1}^{i}frac{f[j]}{(j-1)!}*frac{ 2^{ extrm{C}_{i-j}^{2} } }{(i-j)!}=frac{2^{ extrm{C}_{i}^{2}}}{(i-1)!}$
我们令$A=sum_{i=1}^{n}frac{f[i]}{(i-1)!}*x^i$
$B=sum_{i=0}^{n}frac{2^{ extrm{C}_{i}^{2}}}{i!}*x^i$
$C=sum_{i=1}^{n}frac{2^{ extrm{C}_{i}^{2}}}{(i-1)!}*x^i$
那么$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 ",(int)(1LL*b[n]*fac[n-1]%mod)); return 0; }
By NeighThorn