[LuoguP4841]城市規劃(多項式ln+生成函式)
阿新 • • 發佈:2020-08-03
[LuoguP4841]城市規劃(多項式ln+生成函式)
題面
求\(n\)個頂點的有標號連通簡單無向圖的個數(簡單指的是無重邊自環)。(\(n \leq 10^5\))
分析
\(n\)個點的簡單無向圖有\(2^{\binom{n}{2}}\)個,設G是所有無向圖,那麼G的EGF為
\[G(x)=\sum_{n=0}^{\infin} 2^{\binom{n}{2}} \frac{x^n}{n!} \]
設連通圖的生成函式為\(C(x)\),考慮列舉連通塊個數\(i\),有
\[G(x)=\sum_{i\geq 0}\frac{1}{i!}C^i(x)=\exp(C(x) \]
除\(i!\)是因為連通塊內部的排列順序無關。第二步用了\(\mathrm{e}^x\)
程式碼
#include<cstdio> #include<cstring> #define maxn 400000 #define mod 1004535809 using namespace std; typedef long long ll; inline ll fast_pow(ll x,ll k){ ll ans=1; while(k){ if(k&1) ans=ans*x%mod; x=x*x%mod; k>>=1; } return ans; } inline ll inv(ll x){ return fast_pow(x,mod-2); } const ll G=3,invG=inv(3); int rev[maxn*4+5]; void NTT(ll *x,int n,int type){ for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]); for(int len=1;len<n;len*=2){ int sz=len*2; ll gn1=fast_pow((type==1?G:invG),(mod-1)/sz); for(int l=0;l<n;l+=sz){ int r=l+len-1; ll gnk=1; for(int i=l;i<=r;i++){ ll tmp=x[i+len]; x[i+len]=(x[i]-gnk*tmp%mod+mod)%mod; x[i]=(x[i]+gnk*tmp%mod)%mod; gnk=gnk*gn1%mod; } } } if(type==-1){ ll invn=inv(n); for(int i=0;i<n;i++) x[i]=x[i]*invn%mod; } } void poly_mul(ll *a,ll *b,ll *c,int n,int m){ static ll ta[maxn+5],tb[maxn+5]; int N=1,L=0; while(N<n+m-1){ N*=2; L++; } for(int i=0;i<n;i++) ta[i]=a[i]; for(int i=n;i<N;i++) ta[i]=0; for(int i=0;i<m;i++) tb[i]=b[i]; for(int i=n;i<N;i++) tb[i]=0; for(int i=0;i<N;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); NTT(ta,N,1); NTT(tb,N,1); for(int i=0;i<N;i++) c[i]=ta[i]*tb[i]%mod; NTT(c,N,-1); for(int i=n+m-1;i<N;i++) c[i]=0; } void poly_inv(ll *f,ll *g,int n){ static ll tmp[maxn+5]; if(n==1){ g[0]=inv(f[0]); return; } poly_inv(f,g,(n+1)/2); poly_mul(f,g,tmp,n,n); poly_mul(tmp,g,tmp,n,n); for(int i=0;i<n;i++) g[i]=(2*g[i]-tmp[i]+mod)%mod; } void poly_deriv(ll *f,ll *g,int n){ for(int i=1;i<n;i++) g[i-1]=f[i]*i%mod; g[n-1]=0; } void poly_inter(ll *f,ll *g,int n){ for(int i=n-1;i>=1;i--) g[i]=f[i-1]*inv(i)%mod; g[0]=0; } void poly_ln(ll *f,ll *g,int n){ static ll invf[maxn+5]; poly_inv(f,invf,n); poly_deriv(f,g,n); poly_mul(g,invf,g,n,n); poly_inter(g,g,n*2); for(int i=n;i<n*2;i++) g[i]=0; } void poly_exp(ll *f,ll *g,int n){ static ll lng[maxn+5]; if(n==1){ g[0]=1; return; } poly_exp(f,g,(n+1)/2); poly_ln(g,lng,n); for(int i=0;i<n;i++) lng[i]=(f[i]-lng[i]+mod)%mod; lng[0]++; poly_mul(g,lng,g,n,n); for(int i=n;i<n*2;i++) g[i]=0; } int n; ll fact[maxn+5]; ll c[maxn+5],f[maxn+5]; int main(){ scanf("%d",&n); fact[0]=1; for(int i=1;i<=n;i++) fact[i]=fact[i-1]*i%mod; for(int i=0;i<=n;i++) c[i]=fast_pow(2,1ll*i*(i-1)/2)*inv(fact[i])%mod; poly_ln(c,f,n+1); printf("%lld\n",f[n]*fact[n]%mod); }