洛谷传送门
Codeforces传送门
题意翻译
用 n n n个点组成二叉树,问高度大于等于 h h h的有多少个。
1 ≤ h ≤ 35 1\le h\le 35 1≤h≤35。
解题分析
设 d p [ i ] [ h ] dp[i][h] dp[i][h]表示 i i i个节点, 树高为 h h h的方案数, 那么显然可以通过在根节点拼两棵子树得到新的树。
分开枚举高为
h
−
1
h-1
h−1的子树在哪边, 那么有:
d
p
[
i
]
[
h
]
=
∑
j
=
h
−
1
i
∑
k
=
0
h
−
1
d
p
[
j
]
[
h
−
1
]
×
d
p
[
i
−
j
−
1
]
[
k
]
+
∑
j
=
h
−
1
i
∑
k
=
0
h
−
2
d
p
[
j
]
[
h
−
1
]
×
d
p
[
i
−
j
−
1
]
[
k
]
dp[i][h]=\sum_{j=h-1}^{i}\sum_{k=0}^{h-1}dp[j][h-1]\times dp[i-j-1][k]+\sum_{j=h-1}^{i}\sum_{k=0}^{h-2}dp[j][h-1]\times dp[i-j-1][k]
dp[i][h]=j=h−1∑ik=0∑h−1dp[j][h−1]×dp[i−j−1][k]+j=h−1∑ik=0∑h−2dp[j][h−1]×dp[i−j−1][k]
O
(
n
4
)
O(n^4)
O(n4), 如果做一个前缀和可以做到
O
(
n
3
)
O(n^3)
O(n3), 如果用
F
F
T
FFT
FFT可以优化到
O
(
n
2
l
o
g
(
n
)
)
O(n^2log(n))
O(n2log(n))。
然而已经足够了, 就不搞这么多操作了。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 40
#define ll long long
int n, lim;
ll pre[MX], dp[MX][MX];
ll ans;
int main(void)
{
scanf("%d%d", &n, &lim);
dp[0][0] = 1;
R int i, j, k, h;
for (h = 1; h <= n; ++h)
for (i = h; i <= n; ++i)
{
for (k = h - 1; k < i; ++k)
for (j = 0; j < h - 1; ++j)
dp[i][h] += dp[k][h - 1] * dp[i - k - 1][j] * 2;
for (k = h - 1; k < i; ++k)
dp[i][h] += dp[k][h - 1] * dp[i - k - 1][h - 1];
}
for (i = lim; i <= n; ++i) ans += dp[n][i];
printf("%lld", ans);
}