BZOJ 3456 城市规划

BZOJ 3456 城市规划


Solution:

\(f(n)\)表示n个点的无向简单连通图的个数

\(g(n)\)表示n个点的无向简单图个数

那么有\(g(n)=\sum_{i=1}^{n} \left(\begin{array}{c} n-1 \\ i-1 \end{array} \right) \times f(i) \times g(n-i)\)

然后把组合数展开

\(\frac{g(n)}{(n-1)!}=\sum_{i=1}^{n} \frac{f(i)}{(i-1)!} \times \frac{g(n-i)}{(n-i)!}\)

然后令生成函数

\(F(x)=\sum_{i=1}^{\infty}\frac{f(i)}{(i-1)!}x^{i}\)

\(G(x)=\sum_{i=0}^{\infty}\frac{g(i)}{i!}x^{i}\)

\(C(x)=\sum_{i=1}^{\infty}\frac{g(i)}{(i-1)!}x^{i}\)

然后有 \(F(x)G(x)=C(x)\)        \((\%x^{n+1})\)

然后用多项式求逆求出 \(G^{-1}(x)\),然后 \(\times C(x)\) 得到 \(F(x)\)

\(F(x)\)\(x^{n}\)系数 \(\times (n-1)!\) 就是答案

为什么\(f(0)=0\)\(g(0)=1\)\(c(0)=0\) QwQ

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=500000;
const int mm=1004535809;

long long Ksm(long long a,long long p){
	long long ret=1;
	for(;p;p>>=1,a=a*a%mm){
		if(p&1)ret=ret*a%mm;
	}
	return ret;
}

int rev[maxn];
void NTT(long long *arr,int n,int f){
	int b=0;
	for(int len=1;len<n;len<<=1)++b;
	for(int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(b-1));
	for(int i=0;i<n;++i)if(i<rev[i])swap(arr[i],arr[rev[i]]);
	
	for(int k=1;k<n;k<<=1){
		int p=k+k;
		long long wn=Ksm(3LL,(mm-1LL)/p);
		if(f==-1)wn=Ksm(wn,mm-2LL);
		
		for(int i=0;i<n;i+=p){
			long long w=1;
			for(int j=0;j<k;++j,w=w*wn%mm){
				long long x=arr[i+j],y=arr[i+j+k]*w%mm;
				arr[i+j]=(x+y)%mm;
				arr[i+j+k]=(x-y+mm)%mm;
			}
		}
	}
	
	if(f==-1){
		long long inv=Ksm(n*1LL,mm-2LL);
		for(int i=0;i<n;++i)arr[i]=arr[i]*inv%mm;
	}
}

long long B[maxn],C[maxn];
void DivCon(long long *A,int dg){
	if(dg==1){
		B[0]=Ksm(A[0],mm-2LL);
		return;
	}
	DivCon(A,(dg+1)>>1);
	
	int len=1;
	for(len=1;len<(dg<<1);len<<=1);
	
	for(int i=0;i<dg;++i)C[i]=A[i];
	for(int i=dg;i<len;++i)C[i]=0;
	
	NTT(B,len,1);
	NTT(C,len,1);
	for(int i=0;i<len;++i)B[i]=B[i]*(2-B[i]*C[i]%mm+mm)%mm;
	NTT(B,len,-1);
	
	for(int i=dg;i<len;++i)B[i]=0;
}

int n;
long long ft[maxn];

long long F[maxn],G[maxn],H[maxn];

long long g(int x){
	return Ksm(2LL,x*(x-1LL)/2);
}

int main(){
	scanf("%d",&n);
	ft[0]=1;
	for(int i=1;i<=n;++i)ft[i]=ft[i-1]*i%mm;
	
	for(int i=0;i<=n;++i)G[i]=g(i)*Ksm(ft[i],mm-2LL)%mm;
	for(int i=1;i<=n;++i)H[i]=g(i)*Ksm(ft[i-1],mm-2LL)%mm;
	DivCon(G,n+1);
	
	int len=1;
	for(len=1;len<=(n<<1);len<<=1);
	NTT(B,len,1);
	NTT(H,len,1);
	for(int i=0;i<len;++i)F[i]=B[i]*H[i]%mm;
	NTT(F,len,-1);
	
	long long ans=F[n]*ft[n-1]%mm;
	
	printf("%lld\n",ans);
	
	return 0;
}
posted @ 2018-06-20 15:16  ws_zzy  阅读(199)  评论(0编辑  收藏  举报