题解-LibreOJ-6495「雅礼集训 2018 Day1」树

题目概括征集中~

重金(5 RMB)征集状压 dp 解法~ @所有人

这题也太巧妙了叭! ——Mr.G

Solution 1 : $O(n^4)$

注意到节点 2 的父节点一定为 1;因此可以将以 2 为根的子树与剩余部分分开讨论。

定义状态 $f[i][j]$ 表示有 $i$ 个节点,深度为 $j$ 的方案数。

设以 2 为根的子树中共有 $x$ 个节点。情况一:子树 2 的深度恰好为 $j-1$,剩余部分的深度任意;情况二:子树 2 的深度任意,剩余部分的深度恰好为 $j$。

由于两棵子树的节点编号为 $3…i$ 间的任意整数,所以求出方案数之后需乘上标号的方案数。
$$
f[i][j]=\sum_{x=1}^{i-1}[\sum_{k=1}^{j}f[x][j-1]\times f[i-x][k]\times {i-2\choose x-1}+\sum_{k=1}^{j-2}f[x][k]\times f[i-x][j]\times{i-2\choose x-1}]
$$
对于期望,只需将 $\sum_{i=1}^n f[n][i]\times i$ 除以 $(n-1)!$ 即可。

对于四舍五入,可打表。(正经)

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 30;
const int tb[] = {0, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6};

ll n, p;
ll fac[maxn], inv[maxn], facinv[maxn];

inline int C(int n, int m) {
return fac[n] * facinv[n - m] % p * facinv[m] % p;
}

ll f[maxn][maxn];
ll ans = 0;

int main() {
cin >> n >> p;
fac[0] = fac[1] = inv[1] = facinv[0] = facinv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = (p - p / i) * inv[p % i] % p;
fac[i] = fac[i - 1] * i % p;
facinv[i] = facinv[i - 1] * inv[i] % p;
}
f[1][1] = 1, f[2][2] = 1;
for (int i = 3; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
for (int x = 1; x <= i - 1; ++x) {
int t1 = 0, t2 = 0;
for (int k = 1; k <= j; ++k)
t1 = (t1 + f[x][j - 1] * f[i - x][k] % p * C(i - 2, x - 1) % p) % p;
for (int k = 1; k <= j - 2; ++k)
t2 = (t2 + f[x][k] * f[i - x][j] % p * C(i - 2, x - 1) % p) % p;
f[i][j] = (f[i][j] + t1 + t2) % p;
}
}
}
for (int i = 1; i <= n; ++i)
ans = (ans + f[n][i] * i) % p;
for (int i = 1; i <= n - 1; ++i)
ans = (ans * inv[i]) % p;
cout << tb[n] << endl << ans;
return 0;
}

Solution 2 : $O(2^n*n^2)$

状压 dp 解法

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×