题意
求 n n 个有标号点的无向联通图个数
Solution
发现直接求解很复杂,将其用别的函数表示出来
设为包含 1 1 号节点的节点数为 无向连通图 个数, g(x) g ( x ) 为节点数为 x x 的 无向图 个数
这两个函数有以下关系:
组合数在卷积内不好维护,直接拆开
显然 g(n)=2C2n g ( n ) = 2 C n 2
考虑构建生成函数
可得 A(x)=B(x)C(x) A ( x ) = B ( x ) C ( x )
在 modxn+1 mod x n + 1 条件下, A(x)B−1(x)=C(x) A ( x ) B − 1 ( x ) = C ( x )
所以直接求逆做多项式乘法即可
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int mod = 1004535809 , G = 3 , N = 270000;
int n , m = 1 , rev[N];
int frc[N];
int A[N] , B[N] , C[N];
int INVB[N];
int read() {
int ans = 0 , flag = 1;
char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') flag = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {ans = ans * 10 + ch - '0'; ch = getchar();}
return ans * flag;
}
int qpow(int a , int b) {
int ans = 1;
while(b) {
if(b & 1) ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ans;
}
void dft(int *now , int n , int f) {
for(int i = 0 ; i < n ; ++ i)
if(i < rev[i]) swap(now[i] , now[rev[i]]);
for(int i = 1 ; i < n ; i <<= 1) {
int gn = qpow(G , (mod - 1) / (i << 1));
if(f != 1) gn = qpow(gn , mod - 2);
for(int j = 0 ; j < n ; j += (i << 1)) {
int x , y , g = 1;
for(int k = 0 ; k < i ; ++ k , g = 1ll * g * gn % mod) {
x = now[j + k] , y = 1ll * now[i + j + k] * g % mod;
now[j + k] = (x + y) % mod;
now[i + j + k] = (x - y + mod) % mod;
}
}
}
if(f != 1) {
int ny = qpow(n , mod - 2);
for(int i = 0 ; i < n ; ++ i) now[i] = 1ll * now[i] * ny % mod;
}
}
void inv(int *a , int *b , int deg) {
if(deg == 1) {b[0] = qpow(a[0] , mod - 2); return;}
inv(a , b , (deg + 1) >> 1);
int l = 0 , nn , n = deg * 2;
for(nn = 1 ; nn < n ; nn <<= 1) ++ l;
for(int i = 0 ; i < nn ; ++ i)
rev[i] = (rev[i>>1]>>1) | ((i & 1) << (l - 1));
for(int i = 0 ; i < deg ; ++ i) C[i] = a[i];
for(int i = deg ; i < nn ; ++ i) C[i] = 0;
dft(C , nn , 1); dft(b , nn , 1);
for(int i = 0 ; i < nn ; ++ i) b[i] = 1ll * (2 - 1ll * C[i] * b[i] % mod + mod ) % mod * b[i] % mod;
dft(b , nn , -1);
for(int i = deg ; i < nn ; ++ i) b[i] = 0;
}
int main() {
n = read();
frc[0] = 1;
for(int i = 1 ; i <= n ; ++ i) frc[i] = 1ll * frc[i - 1] * i % mod;
for(int i = 1 ; i <= n ; ++ i)
A[i] = 1ll * qpow(2 , 1ll * i * (i - 1) / 2 % (mod - 1)) * qpow(frc[i - 1] , mod - 2) % mod;
for(int i = 0 ; i <= n ; ++ i)
B[i] = 1ll * qpow(2 , 1ll * i * (i - 1) / 2 % (mod - 1)) * qpow(frc[i] , mod - 2) % mod;
inv(B , INVB , n);
while(m <= n) m <<= 1;
int l = 0 , nn;
for(nn = 1 ; nn <= m ; nn <<= 1) ++ l;
for(int i = 0 ; i < nn ; ++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
dft(INVB , nn , 1); dft(A , nn , 1);
for(int i = 0 ; i < nn ; ++ i) A[i] = 1ll * A[i] * INVB[i] % mod;
dft(A , nn , -1);
printf("%lld\n" , 1ll * A[n] * frc[n - 1] % mod);
return 0;
}