BZOJ 3456: 城市规划

3456: 城市规划

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 640  Solved: 352
[Submit][Status][Discuss]

Description

 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
 好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
 由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.

Input

 仅一行一个整数n(<=130000)
 

Output

 仅一行一个整数, 为方案数 mod 1004535809.

Sample Input

3

Sample Output

4

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

 
原文地址:https://www.cnblogs.com/neighthorn/p/6657930.html