点双连通图计数
求 \(n\) 个点的有标号点双连通图(简单无向图,整个图是一个点双连通分量)的个数,答案对 \(998244353\) 取模。
\(n \leq 10^5\)。
题解
https://www.cnblogs.com/bestwyj/p/12063371.html
设有根连通无向图的指数生成函数是 \(F(x)\)。显然有根就在无根的情况下选一个根出来就行了。
点双肯定从点考虑,分析一下一个连通图点双分解的形态,根节点被若干个点双包含。
设 \(g_i\) 为 \(i\) 个点有根点双图数目。
一个包含根的点双,除了根另有 \(n\) 个点,这 \(n\) 个点都挂着有根连通无向图,可得这一群点的EGF为 \(\sum_{n=1}^\infty g_{n+1} \frac{F(x)^n}{n!}\)。
将点双自由排列(这里也可以理解成集合的组合),要选根再乘上一个 \(x\),得到
\[ F(x)=x \exp\left(\sum_{i=1}^\infty g_{i+1} \frac{F(x)^i}{i!}\right) \]
一开始我想的是点双连通分量之间可以看成共用一个点连接起来的
\[ F(x)=\sum_{i=1}^\infty g_i\frac{x^i}{i!}\exp(iF'(x)-i) \]
但这样会算重。因为根节点可能在多个点双中。
设 \(G(x)=\sum_{i=1}^\infty g_{i+1}\frac{x^i}{i!}\),化简得到
\[ F(x)=x\exp G(F(x)) \]
继续变换得
\[ x=\frac{F(x)}{\exp G(F(x))}\\ \Rightarrow F^{-1}(x)=\frac{x}{\exp G(x)} \]
因此,\(G(x)=\ln \frac{x}{F^{-1}(x)}\),复合逆多项式是不能直接求出来的。
记辅助函数 \(H(x)=\ln \frac{F(x)}{x}\) 则 \(G(x)=H(F^{-1}(x))\)。
代入扩展拉格朗日反演:
\[ [x^n]G(x)=\frac{1}{n} [x^{n-1}]H'(x) \left(\frac{x}{F(x)}\right)^n \]
我们要求的即 \(g_n=[x^{n-1}]G(x)\) 可以单次 \(O(n\log n)\) 计算。注意要特判掉 \(n=1\) 的情况。
CO int N=262144;
int omg[2][N],rev[N];
int fac[N],inv[N],ifac[N];
void NTT(poly&a,int dir){
int lim=a.size(),len=log2(lim);
for(int i=0;i>1]>>1|(i&1)<<(len-1);
for(int i=0;i=1;--i) a[i]=mul(a[i-1],inv[i]);
return a[0]=0,a;
}
poly exp(poly a){
int n=a.size();
poly b={1}; // a[0]=0
if(n==1) return b;
a.resize(1<<(int)ceil(log2(n)));
for(int lim=2;lim<2*n;lim<<=1){
b.resize(lim);poly c=log(b);
c[0]=add(1+a[0],mod-c[0]);
for(int i=1;i();
if(n==1) {puts("1");return;}
poly f(n+2);
for(int i=0;i<=n+1;++i) f[i]=mul(fpow(2,(int64)i*(i-1)/2%(mod-1)),ifac[i]);
f=log(f);
for(int i=0;i<=n+1;++i) f[i]=mul(f[i],i);
for(int i=0;i<=n;++i) f[i]=f[i+1];
f.resize(n+1);
poly g=f=log(f);
for(int i=0;i