题面
解析
设$g_i$为$i$个点的无向图个数,即$g_i=2^{frac{i*(i-1)}{2}}$,$f_i$为无向连通图个数,枚举点1所在连通块,有下式:$$g_i=sum_{j=1}^i inom{i-1}{j-1}f_i g_{i-j} \ g_i=sum_{j=1}^i frac{(i-1)!}{(j-1)!(i-j)!}f_ig_{i-j}\ frac{g_i}{(i-1)!}=sum_{j=1}^{i}frac{f_j}{(j-1)!}*frac{g_{i-j}}{(i-j)!}$$
设$A(x)=sum_{i=1}^{infty}frac{g_i}{(i-1)!}x^i$, $F(x)=sum_{i=1}^{infty}frac{f_i}{(i-1)!}x^i$, $B(x)=sum_{i=0}^{infty}frac{g_i}{i!}x^i$,则:$$A(x)=F(x)B(x)\ F(x)=frac{A(x)}{B(x)}$$
多项式求逆即可
复杂度$O(N log N)$
代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 260005, mod = 1004535809, g = 3; int add(int x, int y) { return x + y < mod? x + y: x + y - mod; } int rdc(int x, int y) { return x - y < 0? x - y + mod: x - y; } ll qpow(ll x, ll y) { y %= (mod - 1); ll ret = 1; while(y) { if(y&1) ret = ret * x % mod; x = x * x % mod; y >>= 1; } return ret; } int n, lim, bit, rev[maxn<<1]; ll ginv, fac[maxn], fnv[maxn], c[maxn<<1], G[maxn<<1], gg[maxn<<1], f[maxn<<1]; void init() { ginv = qpow(g, mod - 2); fac[0] = 1; for(int i = 1; i <= n; ++i) fac[i] = i * fac[i-1] % mod; fnv[n] = qpow(fac[n], mod - 2); G[n] = fnv[n] * qpow(2, 1LL * n * (n - 1) >> 1) % mod; for(int i = n - 1; i >= 0; --i) { fnv[i] = fnv[i+1] * (i + 1) % mod; f[i+1] = fnv[i] * qpow(2, 1LL * i * (i + 1) >> 1) % mod; G[i] = fnv[i] * qpow(2, 1LL * i * (i - 1) >> 1) % mod; } } void NTT_init(int x) { lim = 1; bit = 0; while(lim <= x) { lim <<= 1; ++ bit; } for(int i = 1; i < lim; ++i) rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (bit - 1)); } void NTT(ll *x, int y) { for(int i = 1; i < lim; ++i) if(i < rev[i]) swap(x[i], x[rev[i]]); ll wn, w, u, v; for(int i = 1; i < lim; i <<= 1) { wn = qpow((y == 1)? g: ginv, (mod - 1) / (i << 1)); for(int j = 0; j < lim; j += (i << 1)) { w = 1; for(int k = 0; k < i; ++k) { u = x[j+k]; v = x[j+k+i] * w % mod; x[j+k] = add(u, v); x[j+k+i] = rdc(u, v); w = w * wn % mod; } } } if(y == -1) { ll linv = qpow(lim, mod - 2); for(int i = 0; i < lim; ++i) x[i] = x[i] * linv % mod; } } void get_inv(ll *x, ll *y, int len) { if(len == 1) { x[0] = qpow(y[0], mod - 2); return ; } get_inv(x, y, (len + 1) >> 1); for(int i = 0; i < len; ++i) c[i] = y[i]; NTT_init(len << 1); NTT(x, 1); NTT(c, 1); for(int i = 0; i < lim; ++i) { x[i] = rdc(add(x[i], x[i]), (c[i] * x[i] % mod) * x[i] % mod); c[i] = 0; } NTT(x, -1); for(int i = len; i < lim; ++i) x[i] = 0; } int main() { scanf("%d", &n); init(); get_inv(gg, G, n + 1); NTT_init((n + 1) << 1); NTT(gg, 1); NTT(f, 1); for(int i = 0; i < lim; ++i) f[i] = f[i] * gg[i] % mod; NTT(f, -1); printf("%lld ", f[n] * fac[n-1] % mod); return 0; }