正题
题目链接:https://www.luogu.org/problemnew/show/P4841
题目大意
求nnn个点的简单联通无向图的个数。
解题思路
首先考虑n2n^2n2,我们设gig_igi表示iii个点的简单无向图的个数,显然gi=2n(n−1)2g_i=2^{\frac{n(n-1)}{2}}gi=22n(n−1)
然后我们设fif_ifi表示iii个点的简单无向联通图的个数,然后我们只要固定一个联通块大小为k(k<i)k(k<i)k(k<i)然后剩下的点都不与其联通就可以去掉不连通的。
也就是fn=gn−∑i=1n−1fi∗Cn−1i−1∗gn−if_n=g_n-\sum_{i=1}^{n-1}f_i*C_{n-1}^{i-1}*g_{n-i}fn=gn−i=1∑n−1fi∗Cn−1i−1∗gn−i
这就是O(n2)O(n^2)O(n2)
之后我们考虑优化,将CCC拆开
fn=gn−∑i=1n−1fi∗(i−1)!(n−i)!(i−1)!∗gn−if_n=g_n-\sum_{i=1}^{n-1}f_i*\frac{(i-1)!}{(n-i)!(i-1)!}*g_{n-i}fn=gn−i=1∑n−1fi∗(n−i)!(i−1)!(i−1)!∗gn−i
然后将nnn的项提出
fn=gn−∑i=1n−1fi∗(n−1)!(n−i)!(i−1)!∗gn−if_n=g_n-\sum_{i=1}^{n-1}f_i*\frac{(n-1)!}{(n-i)!(i-1)!}*g_{n-i}fn=gn−i=1∑n−1fi∗(n−i)!(i−1)!(n−1)!∗gn−i
gn(n−1)!=∑i=1nfi(i−1)!gn−i(n−i)!\frac{g_n}{(n-1)!}=\sum_{i=1}^n\frac{f_i}{(i-1)!}\frac{g_{n-i}}{(n-i)!}(n−1)!gn=i=1∑n(i−1)!fi(n−i)!gn−i
然后使用NTTNTTNTT卷起来
F(x)=∑i=1+∞fi(i−1)!xiF(x)=\sum_{i=1}^{+\infty}\frac{f_i}{(i-1)!}x^iF(x)=i=1∑+∞(i−1)!fixi
G(x)=∑i=0+∞gn−i(n−i)!xiG(x)=\sum_{i=0}^{+\infty}\frac{g_{n-i}}{(n-i)!}x^iG(x)=i=0∑+∞(n−i)!gn−ixi
H(x)=∑n=1+∞gn(n−1)!xnH(x)=\sum_{n=1}^{+\infty}\frac{g_n}{(n-1)!}x^nH(x)=n=1∑+∞(n−1)!gnxn
上两个的iii与最后一个的nnn同理,所以现在有
H(x)=F(x)G(x)H(x)=F(x)G(x)H(x)=F(x)G(x)
F(x)=H(x)G(x)−1F(x)=H(x)G(x)^{-1}F(x)=H(x)G(x)−1
现在我们要求F(x)F(x)F(x)而H(x)H(x)H(x)和G(x)G(x)G(x)都知道。
那么我们将G(x)G(x)G(x)进行求逆后用NTTNTTNTT与H(x)H(x)H(x)相乘就好了。
codecodecode
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const ll N=131000,XJQ=1004535809;
ll n,fac[N],inv[N],r[N*4],Gi;
ll power(ll x,ll b)
{ll ans=1;while(b){if(b&1) ans=ans*x%XJQ;x=x*x%XJQ;b>>=1;}return ans;
}
struct Poly{ll x[N*4];void cpy(Poly &a,ll len){for(ll i=0;i<len;i++)x[i]=a.x[i];}void reset(ll len){for(ll i=0;i<len;i++)x[i]=0;}void ntt(ll n,ll op){for(ll i=1;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)?n>>1:0);for(ll i=0;i<n;i++)if(i<r[i])swap(x[i],x[r[i]]);for(ll p=2;p<=n;p<<=1){ll len=p>>1,tmp=power(3,(XJQ-1)/p);if(op==-1)tmp=power(tmp,XJQ-2);for(ll k=0;k<n;k+=p){ll buf=1;for(ll i=k;i<k+len;i++){ll tt=buf*x[len+i]%XJQ;x[len+i]=(x[i]-tt+XJQ)%XJQ;x[i]=(x[i]+tt)%XJQ;buf=buf*tmp%XJQ;}}}}
};
Poly get_inv(Poly &a,Poly &b,Poly &c,ll n){if(a.x[0]==1) b.x[0]=1;else b.x[0]=power(a.x[0],XJQ-2);for(ll w=1;(1<<(w-1))<n;++w){ll len=(1<<w);c.cpy(a,len);c.ntt(len*2,1);b.ntt(len*2,1);for(ll i=0;i<(len<<1);i++)b.x[i]=(2-b.x[i]*c.x[i]%XJQ+XJQ)*b.x[i]%XJQ;b.ntt(len*2,-1);ll inv=power(len*2,XJQ-2);for(ll i=0;i<len;i++)b.x[i]=b.x[i]*inv%XJQ;for(ll i=len;i<len*2;i++) b.x[i]=0;}return b;
}
Poly H,Ginv,a,b;
int main()
{scanf("%lld",&n);n++;fac[0]=fac[1]=inv[0]=inv[1]=1;for(ll i=2;i<=n;i++){inv[i]=XJQ-(XJQ/i)*inv[XJQ%i]%XJQ;fac[i]=fac[i-1]*inv[i]%XJQ;}Ginv.x[0]=1;for(ll i=1;i<n;i++){ll tmp=power(2,i*(i-1)/2%(XJQ-1));H.x[i]=tmp*fac[i-1]%XJQ,Ginv.x[i]=tmp*fac[i]%XJQ;}Ginv=get_inv(Ginv,a,b,n);ll len=1,w=0;while(len<(n<<1)) len<<=1,w++;for(ll i=n;i<len;i++) Ginv.x[i]=0;H.ntt(len,1);Ginv.ntt(len,1);for(ll i=0;i<=len;i++)H.x[i]=H.x[i]*Ginv.x[i]%XJQ;H.ntt(len,-1);printf("%lld",power(inv[2],w)*H.x[n-1]%XJQ*power(fac[n-2],XJQ-2)%XJQ);
}