求\(n\)个点的简单(无重边无自环)有标号无向连通图数目。
设\(f(n)\)为点数为\(n\)的无向连通图的数量,\(g(n)\)为点数为\(n\)的无向图的数量,可以知道:
可以这么理解,\(n\)个点中取两个点连边,一共有\(C_n^2\)种,每个边存在连或不连两种可能。
同时有:
这个可以这么理解,对于一号点,枚举它所在的连通块中有多少个点。
代入\(g(n)\)可得:
化简一下:
设
那么有:
NTT+多项式求逆求解。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 6e5+10;
const ll mod = 1004535809;
const int G = 3;
int n;
ll inv[maxn];   //逆元
ll fiv[maxn];   //逆元的阶乘
ll g1[maxn], g2[maxn], g3[maxn];
ll qmi(ll a, ll b)
{
    ll res = 1;
    while(b)
    {
        if(b&1) res = (res*a)%mod;
        b >>= 1;
        a = (a*a)%mod;
    } return res%mod;
}
int limit, len, rev[maxn];
void NTT(ll *c, int op)
{
    for(int i = 1; i <= limit; i++)
        if(i < rev[i]) swap(c[i], c[rev[i]]);
    for(int mid = 1; mid < limit; mid <<= 1)
    {
        ll gn = qmi(G, (mod-1)/(mid<<1));
        if(op == -1) gn = qmi(gn, mod-2);
        for(int j = 0, R = mid<<1; j < limit; j += R)
        {
            ll g = 1;
            for(int k = 0; k < mid; k++, g = (g*gn)%mod)
            {
                ll x = c[j+k], y = g*c[j+k+mid]%mod;
                c[j+k] = (x+y)%mod;
                c[j+k+mid] = (x-y+mod)%mod;
            }
        }
    }
    if(op == 1) return;
    ll inv = qmi(limit, mod-2);
    for(int i = 0; i <= limit; i++) c[i] = c[i]*inv%mod;
}
ll tmp[maxn];
void get_inv(ll *a, ll *b, int deg)
{
	if(deg == 1)
	{
		b[0] = qmi(a[0], mod-2);
		return;
	}
	get_inv(a, b, (deg+1)>>1);
	len = 0, limit = 1;
	while(limit <= (deg+deg)) limit <<= 1, len++;
	for(int i = 1; i <= limit; i++)
		rev[i] = (rev[i>>1]>>1)|((i&1)<<(len-1));
	for(int i = 0; i < deg; i++) tmp[i] = a[i];
	for(int i = deg; i <= limit; i++) tmp[i] = 0;
	NTT(tmp, 1), NTT(b, 1);
	for(int i = 0; i <= limit; i++)
		b[i] = 1ll*(2-1ll*tmp[i]*b[i]%mod+mod)%mod*b[i]%mod;
	NTT(b, -1);
	for(int i = deg; i <= limit; i++) b[i] = 0;
}
int main()
{
    scanf("%d", &n); n += 1;
    fiv[0]=fiv[1]=inv[0]=inv[1]=1;
    for(int i = 2; i <= n; i++)
    {
        inv[i] = (ll(mod-mod/i)*inv[mod%i])%mod;
        fiv[i] = fiv[i-1]*inv[i]%mod;
    }
    g3[0] = 1;
    for(ll i = 1; i < n; i++)
    {
        ll tmp = qmi(2, (i*(i-1)/2)%(mod-1))%mod;//欧拉降幂
        g1[i] = tmp*fiv[i-1]%mod;
        g3[i] = tmp*fiv[i]%mod;
    }
    get_inv(g3, g2, n);
    NTT(g1, 1); NTT(g2, 1);
    for(int i = 0; i <= limit; i++) g1[i] = g1[i]*g2[i]%mod;
    NTT(g1, -1);
    ll ans = g1[n-1]%mod*qmi(fiv[n-2], mod-2)%mod;
    cout << ans << endl;
    return 0;
}
原文:https://www.cnblogs.com/zxytxdy/p/12848328.html