LL Work(int n, int v){ int x, y; for (int i = 1; i < n; ++i) { scanf("%d%d", &x, &y); S.insert(std::make_pair(x, y)); S.insert(std::make_pair(y, x)); } int t = n; for (int i = 1; i < n; ++i) { scanf("%d%d", &x, &y); if (S.count(std::make_pair(x, y))) --t; } returnpow_mod(v, t); } };
voiddp(int x, int fa){ t[x] = 1; g[x] = K; for (int i = pre[x]; ~i; i = nxt[i]) if (to[i] != fa) { int y = to[i]; dp(y, x); g[x] = (g[x] + g[y] * pow_mod(g[y] + t[y], mod - 2)) % mod; t[x] = t[x] * (g[y] + t[y]) % mod; } g[x] = g[x] * t[x] % mod; }
LL Work(int n, int y){ if (y == 1) returnpow_mod(n, n - 2); memset(pre, -1, sizeof pre); for (int i = 1, x, y; i < n; ++i) { scanf("%d%d", &x, &y); addEdge(x, y); } K = (LL)n * y % mod * pow_mod(1 - y, mod - 2) % mod; dp(1, 0); return g[1] * pow_mod(n, mod - 3) % mod * pow_mod(1 - y, n) % mod; } };
voidInit(){ inv[1] = 1; for (int i = 2; i < N; ++i) inv[i] = -(mod / i) * inv[mod % i] % mod; fac[0] = ifac[0] = 1; for (int i = 1; i < N; ++i) { fac[i] = fac[i - 1] * i % mod; ifac[i] = ifac[i - 1] * inv[i] % mod; } }
voidInitNTT(int n){ len = 1; int k = 0; while (len <= n) len <<= 1, k++; for (int i = 1; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1)); omega[0] = inv_omega[0] = 1; LL v = pow_mod(g, (mod - 1) / len); for (int i = 1; i < len; ++i) inv_omega[len - i] = omega[i] = v * omega[i - 1] % mod; }
voidNTT(LL *A, const LL *w){ for (int i = 0; i < len; ++i) if (i < rev[i]) std::swap(A[i], A[rev[i]]); for (int h = 1; h < len; h <<= 1) for (int t = len / (h * 2), j = 0; j < len; j += h * 2) { const LL *wn = w; for (int i = j; i < j + h; ++i) { LL _t1 = A[i], _t2 = A[i + h] * *wn % mod; A[i] = (_t1 + _t2) % mod; A[i + h] = (_t1 - _t2) % mod; wn += t; } } if (w == inv_omega) for (int i = 0, v = -(mod - 1) / len; i < len; ++i) A[i] = A[i] * v % mod; }
voidPolyInv(const LL *A, int n, LL *B){ if (n == 1) { B[0] = pow_mod(A[0], mod - 2); return; } int m = (n + 1) / 2; PolyInv(A, m, B);
static LL tA[N], tB[N]; InitNTT(n * 2); for (int i = 0; i < n; ++i) tA[i] = A[i]; for (int i = n; i < len; ++i) tA[i] = 0; for (int i = 0; i < m; ++i) tB[i] = B[i]; for (int i = m; i < len; ++i) tB[i] = 0; NTT(tA, omega); NTT(tB, omega); for (int i = 0; i < len; ++i) tB[i] = (2 - tA[i] * tB[i]) % mod * tB[i] % mod; NTT(tB, inv_omega); for (int i = 0; i < n; ++i) B[i] = tB[i]; }
voidPolyLn(const LL *A, int n, LL *B){ static LL tA[N], tB[N]; InitNTT(n * 2); PolyInv(A, n, tA); for (int i = n; i < len; ++i) tA[i] = 0; for (int i = 1; i < n; ++i) tB[i - 1] = A[i] * i % mod; for (int i = n - 1; i < len; ++i) tB[i] = 0; NTT(tA, omega); NTT(tB, omega); for (int i = 0; i < len; ++i) tB[i] = tA[i] * tB[i] % mod; NTT(tB, inv_omega); B[0] = 0; for (int i = 1; i < n; ++i) B[i] = tB[i - 1] * inv[i] % mod; }
voidPolyExp(const LL *A, int n, LL *B){ if (n == 1) { B[0] = 1; return; } int m = (n + 1) / 2; PolyExp(A, m, B); for (int i = m; i < n; ++i) B[i] = 0;
static LL tA[N], tB[N]; InitNTT(n * 2); PolyLn(B, n, tA); for (int i = 0; i < n; ++i) tA[i] = ((i == 0) + A[i] - tA[i]) % mod; for (int i = n; i < len; ++i) tA[i] = 0; for (int i = 0; i < m; ++i) tB[i] = B[i]; for (int i = m; i < len; ++i) tB[i] = 0; NTT(tA, omega); NTT(tB, omega); for (int i = 0; i < len; ++i) tB[i] = tA[i] * tB[i] % mod; NTT(tB, inv_omega); for (int i = 0; i < n; ++i) B[i] = tB[i]; }
LL A[N], B[N];
LL Work(int n, int y){ if (y == 1) returnpow_mod(n, 2 * (n - 2)); Init(); LL k = (LL)n * n % mod * y % mod * pow_mod(1 - y, mod - 2) % mod; for (int i = 1; i <= n; ++i) A[i] = pow_mod(i, i) * ifac[i] % mod * k % mod; PolyExp(A, n + 1, B); returnpow_mod(1 - y, n) * fac[n] % mod * pow_mod(inv[n], 4) % mod * B[n] % mod; } };
intmain(){ freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); int n, y, op; scanf("%d%d%d", &n, &y, &op); if (op == 0) printf("%lld\n", (Task1::Work(n, y) + mod) % mod); if (op == 1) printf("%lld\n", (Task2::Work(n, y) + mod) % mod); if (op == 2) printf("%lld\n", (Task3::Work(n, y) + mod) % mod); }
Prufer 序列
如果给定了一颗森林,连通块大小分别为 a1…ak,求其加边变成树的方案数:
可以把每个连通块看成一个点,在这些点间建出一棵树;然后如果第 i 个点的度数为 ti,就多乘上 aiti 表示每条边都会在这个连通块里选一个点作为端点。
根据 Prufer 序列,这 k 个点形成的树唯一对应一个长为 k−2 的、每个数在 [1,k] 之间的序列;且每个点的度数等于它在序列里出现的次数+1。