BZOJ3456 城市规划 【生成函数】【FFT】
题目分析:
容易想到生成函数的构造方法。
令g(n)表示n个点的无向图个数,f(n)表示n个点的无向连通图的个数。式子是显然的。
容易发现式子是卷积的形式,写出生成函数,然后多项式求逆后多项式乘法即可。
代码:
#include<bits/stdc++.h> using namespace std; int n; const int maxn = 800000; const int mod = 1004535809; const int gg = 3; int A[maxn],B[maxn],IB[maxn],B0[maxn],F[maxn]; int fac[maxn/4],ord[maxn]; int fast_pow(int now,long long pw){ if(pw == 0) return 1; if(pw == 1) return now; int z = fast_pow(now,pw/2); z = (1ll*z*z)%mod; if(pw & 1) z = (1ll*z*now)%mod; return z; } void FFT(int *d,int len,int dr){ for(int i=0;i<len;i++) if(ord[i] < i) swap(d[i],d[ord[i]]); for(int i=1;i<len;i<<=1){ int wn = fast_pow(gg,(mod-1)/(i<<1)); if(dr == -1) wn = fast_pow(wn,mod-2); for(int j=0;j<len;j+=(i<<1)){ int w = 1; for(int k=0;k<i;k++,w=(1ll*w*wn)%mod){ int x = d[j+k],y = (1ll*w*d[j+k+i])%mod; d[j+k] = (x+y)%mod; d[j+k+i] = (x-y)%mod; if(d[j+k+i] < 0) d[j+k+i]+=mod; } } } if(dr == -1){ int iv = fast_pow(len,mod-2); for(int i=0;i<len;i++) d[i] = (1ll*d[i]*iv)%mod; } } void GetA(){ for(int i=0;i<=n;i++) A[i] = (1ll*fast_pow(2,1ll*i*(i-1)/2)*fast_pow(fac[i-1],mod-2))%mod; } void GetB(){ for(int i=0;i<=n;i++) B[i] = (1ll*fast_pow(2,1ll*i*(i-1)/2)*fast_pow(fac[i],mod-2))%mod; } void Inv(){ IB[0] = fast_pow(B[0],mod-2); int res = 1; while(res < n+1) res=res<<1; for(int i=2,j=1;i<=res;i<<=1,j++){ int bit = i*2,om = j+1; for(int k=0;k<i;k++) B0[k] = B[k]; for(int k=0;k<bit;k++) ord[k]=(ord[k>>1]>>1)+((k&1)<<om-1); FFT(IB,bit,1);FFT(B0,bit,1); for(int k=0;k<bit;k++) B0[k]=(1ll*B0[k]*((1ll*IB[k]*IB[k])%mod))%mod; for(int k=0;k<bit;k++) IB[k] = (1ll*2*IB[k]-B0[k]+mod)%mod; FFT(IB,bit,-1); for(int k=i;k<2*i;k++) IB[k] = 0; } for(int i=n;i<=res;i++) IB[i] = 0; } void Multi(){ int res = 1,len = 0; while(res < 2*n+1)res = res<<1,len++; for(int i=0;i<res;i++) ord[i]=(ord[i>>1]>>1)+((i&1)<<len-1); FFT(IB,res,1);FFT(A,res,1); for(int i=0;i<res;i++) F[i] = (1ll*A[i]*IB[i])%mod; FFT(F,res,-1); } void work(){fac[0] = 1; for(int i=1;i<=n;i++) fac[i] = (1ll*fac[i-1]*i)%mod; GetA(); GetB(); Inv(); Multi(); F[n] = (1ll*F[n]*fac[n-1])%mod; printf("%d",F[n]); } int main(){ scanf("%d",&n); work(); return 0; }