看来我得恶补组合数学了...
先回忆一下指数生成函数乘积的性质:若$\begin{align*}A_e(x)=\sum\limits_{n=0}^\infty a_n\dfrac{x^n}{n!},B_e(x)=\sum\limits_{n=0}^\infty b_n\dfrac{x^n}{n!}\end{align*}$,那么$\begin{align*}A_e(x)B_e(x)=\sum\limits_{n=0}^\infty c_n\dfrac{x^n}{n!}\end{align*}$,其中$\begin{align*}c_n=\sum\limits_{k=0}^n\binom nka_kb_{n-k}\end{align*}$,相当于普通卷积前面多一个组合数的系数
回到本题,设答案为$f_n$,它的指数生成函数为$F(x)$,那么$n![x^n]\dfrac{F^m(x)}{m!}$计数了$n$个带标号点的图被分成$m$个连通块的方案数(先取$m$组点,把它们分别连成连通块,最后消序,在外面乘一个阶乘是为了抵消指数生成函数的阶乘)
对$m$求和,我们就得到了所有不同的图的数量,这个可以直接算:$2^\binom n2$(两两选点,连/不连边),设它的指数生成函数为$G(x)$
于是我们有$\begin{align*}G(x)=\sum\limits_{m=0}^\infty\dfrac{F^m(x)}{m!}=e^{F(x)}\end{align*}$(从$0$开始求和是因为$G(x)$的常数项为$1$,而$\dfrac{F^0(x)}{0!}$刚好也是$1$),也就是$F(x)=\ln G(x)$
多项式求自然对数:给定$G(x)$,求$F(x)=\ln G(x)$
$\begin{align*}F(x)&=\ln G(x)\\F‘(x)&=\dfrac{G‘(x)}{G(x)}\\F(x)&=\int\dfrac{G‘(x)}{G(x)}dx\end{align*}$
所以直接多项式求逆,微分和积分都是$O(n)$的,总时间复杂度$O(n\log_2n)$
#include<stdio.h> #include<string.h> const int mod=1004535809; typedef long long ll; int mul(int a,int b){return a*(ll)b%mod;} int ad(int a,int b){return(a+b)%mod;} int de(int a,int b){return(a-b)%mod;} int rev[300010],N,iN; int pow(int a,ll b){ int s=1; while(b){ if(b&1)s=mul(s,a); a=mul(a,a); b>>=1; } return s; } void pre(int n){ int i,k; for(N=1,k=0;N<n;N<<=1)k++; for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1)); iN=pow(N,mod-2); } void swap(int&a,int&b){a^=b^=a^=b;} void ntt(int*a,int on){ int i,j,k,t,w,wn; for(i=0;i<N;i++){ if(i<rev[i])swap(a[i],a[rev[i]]); } for(i=2;i<=N;i<<=1){ wn=pow(3,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i)); for(j=0;j<N;j+=i){ w=1; for(k=0;k<i>>1;k++){ t=mul(w,a[i/2+j+k]); a[i/2+j+k]=de(a[j+k],t); a[j+k]=ad(a[j+k],t); w=mul(w,wn); } } } if(on==-1){ for(i=0;i<N;i++)a[i]=mul(a[i],iN); } } int t0[300010]; void getinv(int*a,int*b,int n){ if(n==1){ b[0]=pow(a[0],mod-2); return; } int i; getinv(a,b,n>>1); pre(n<<1); memset(t0,0,sizeof(t0)); for(i=0;i<n;i++)t0[i]=a[i]; ntt(t0,1); ntt(b,1); for(i=0;i<N;i++)b[i]=mul(b[i],de(2,mul(b[i],t0[i]))); ntt(b,-1); for(i=n;i<N;i++)b[i]=0; } int t1[300010],t2[300010],inv[300010]; void getln(int*a,int n){ int i; getinv(a,t1,n); for(i=1;i<n;i++)t2[i-1]=mul(i,a[i]); ntt(t1,1); ntt(t2,1); for(i=0;i<N;i++)a[i]=mul(t1[i],t2[i]); ntt(a,-1); for(i=n-1;i>0;i--)a[i]=mul(a[i-1],inv[i]); a[0]=0; for(i=n;i<N;i++)a[i]=0; } #define N 300000 int fac[300010],rfac[300010],a[300010]; int main(){ int n,i; scanf("%d",&n); fac[0]=1; for(i=1;i<=N;i++)fac[i]=mul(fac[i-1],i); rfac[N]=pow(fac[N],mod-2); for(i=N;i>0;i--)rfac[i-1]=mul(rfac[i],i); for(i=1;i<=N;i++)inv[i]=mul(rfac[i],fac[i-1]); for(i=0;i<=n;i++)a[i]=mul(pow(2,i*(ll)(i-1)/2),rfac[i]); for(i=1;i<n+1;i<<=1); getln(a,i); printf("%d",(mul(a[n],fac[n])+mod)%mod); }