[poly计数] [集训队作业2013]城市规划
记 \(f_i\) 为 \(i\) 个点的简单有标号无向连通图的数目, \(g_i = 2^{\binom i 2}\) 为 \(i\) 个点的简单有标号无向图的数目,
枚举 \(1\) 号点所在联通块的大小,有: \(g_n = \sum\limits_{i=1}^n\dbinom{n-1}{i-1}f_i g_{n-i}\)
拆掉组合数,\(\dfrac {g_n} {(n-1)!} = \sum\limits_{i=1}^n\dfrac {f_i}{(i-1)!}\dfrac {g_{n-i}} {(n-i)!}\)
记 \(H(x) = \sum\limits_{i=1}^n\dfrac{g_i}{(i-1)!},F(x) = \sum\limits_{i=1}^n \dfrac {f_i}{(i-1)!},G(x) = \sum\limits_{i=0}^n\dfrac{g_i}{i!}\)
则 \(H(x) \equiv F(x)G(x) \pmod {x^{n+1}}\)
要求的是 \([x^n]F(x)\),则 \(F(x) \equiv H(x)G'(x)\pmod{x^{n+1}}\),答案即为 \((n-1)![x^n]F(x)\)。
\(\texttt{Code:}\)
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
int read() {
int x = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
const int cmd = 1004535809;
int fpow(int a, ll b) {
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % cmd)
if (b & 1) res = 1ll * res * a % cmd;
return res;
}
int add(int a, int b) {a += b; return a < cmd ? a : a - cmd;}
int sub(int a, int b) {a -= b; return a < 0 ? a + cmd : a;}
const int N = (1 << 19) + 5;
namespace Poly {
int rev[N], w[N], yg = 3, invyg = fpow(3, cmd - 2), inv[N];
void ntt(int *f, int n, int tp) {
for (int i = 1; i < n; i++) {
rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);
if (i < rev[i]) swap(f[i], f[rev[i]]);
}
for (int len = 2; len <= n; len <<= 1) {
int w0 = fpow(tp ? yg : invyg, (cmd - 1) / len); w[0] = 1;
for (int i = 1; i < (len >> 1); i++) w[i] = 1ll * w[i - 1] * w0 % cmd;
for (int s = 0; s < n; s += len)
for (int i = 0; i < (len >> 1); i++) {
int cur = 1ll * f[s + (len >> 1) + i] * w[i] % cmd;
f[s + (len >> 1) + i] = sub(f[s + i], cur);
f[s + i] = add(f[s + i], cur);
}
}
if (!tp) {
int invn = fpow(n, cmd - 2);
for (int i = 0; i < n; i++) f[i] = 1ll * f[i] * invn % cmd;
}
}
void tms(int *f, int *g, int n) {
for (int i = 0; i < n; i++) f[i] = 1ll * f[i] * g[i] % cmd;
}
void invp(int *f, int m) {
static int A[N], B[N], C[N];
int n = 1; for (; n < m; n <<= 1);
A[0] = fpow(f[0], cmd - 2);
for (int len = 2; len <= n; len <<= 1) {
for (int i = 0; i < (len >> 1); i++)
B[i] = (A[i] << 1) % cmd;
memcpy(C, f, sizeof(int)*len);
ntt(A, len << 1, 1); tms(A, A, len << 1);
ntt(C, len << 1, 1); tms(A, C, len << 1);
ntt(A, len << 1, 0); memset(A + len, 0, sizeof(int)*len);
for (int i = 0; i < len; i++)
A[i] = sub(B[i], A[i]);
}memcpy(f, A, sizeof(int)*m);
memset(A, 0, sizeof(int)*n);
memset(B, 0, sizeof(int)*n);
memset(C, 0, sizeof(int)*(n << 1));
}
void NTT(int *f, int *g, int m) {
int n = 1; for (; n <= m + m; n <<= 1);
ntt(f, n, 1); ntt(g, n, 1);
tms(f, g, n); ntt(f, n, 0);
}
}using namespace Poly;
int n, g[N], h[N], fac[N], ifac[N];
int main() {
#ifdef LOCAL
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
n = read();
fac[0] = ifac[0] = 1;
for (int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % cmd;
ifac[n] = fpow(fac[n], cmd - 2);
for (int i = n - 1; i; i--) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % cmd;
g[0] = g[1] = h[1] = 1;
for (int i = 2; i <= n; i++) g[i] = 1ll * fpow(2, 1ll * i * (i - 1) / 2) * ifac[i] % cmd;
for (int i = 2; i <= n; i++) h[i] = 1ll * fpow(2, 1ll * i * (i - 1) / 2) * ifac[i - 1] % cmd;
invp(g, n + 1); NTT(g, h, n);
g[n] = 1ll * g[n] * fac[n - 1] % cmd;
printf("%d", g[n]);
return 0;
}

浙公网安备 33010602011771号