题目
题目描述
农民约翰准备购买一群新奶牛。 在这个新的奶牛群中, 每一个母亲奶牛都生两小奶牛。这些奶牛间的关系可以用二叉树来表示。这些二叉树总共有
N
(
3
≤
N
≤
200
)
N(3\le N\le 200)
N(3≤N≤200) 个节点。这些二叉树有如下性质:
- 每一个节点的度是 0 0 0 或 2 2 2 。度是这个节点的孩子的数目。
- 树的高度等于 K ( 1 < K < 100 ) K(1 < K < 100) K(1<K<100) 。高度是从根到任何叶子的最长的路径上的节点的数目;叶子是指没有孩子的节点。
有多少不同的家谱结构?如果一个家谱的树结构不同于另一个的,那么这两个家谱就是不同的。
输出可能的家谱树的个数除以 9901 9901 9901 的余数。
输入格式
一行两个正整数
n
,
k
n,k
n,k ,含义见题面。
输出格式:
一行一个非负整数,表示不同的家谱结构的数目除以
9901
9901
9901 的余数。
数据范围与约定
对于
100
%
100\%
100%的数据,
n
≤
200
,
k
≤
100
n\le 200,k\le 100
n≤200,k≤100 。
思路
f ( i , j ) f(i,j) f(i,j) 表示有 i i i 个节点,深度 不超过 j j j ,能够形成的家谱树的数量。
那么枚举左子树的节点个数 x x x (右字数节点数自然为 i − x − 1 i-x-1 i−x−1 ),根据乘法原理,有
f ( i , j ) = ∑ x = 0 i − 1 f ( x , j − 1 ) f ( i − x − 1 , j − 1 ) f(i,j)=\sum_{x=0}^{i-1}f(x,j-1)f(i-x-1,j-1) f(i,j)=x=0∑i−1f(x,j−1)f(i−x−1,j−1)
这是 O ( n 2 k ) \mathcal O(n^2k) O(n2k) 的,可以接受。但我们要求的不是 f ( n , k ) f(n,k) f(n,k) !
因为 f ( n , k ) f(n,k) f(n,k) 包含了深度为 1 1 1 到 k k k 的所有可能。我们想知道的是深度 恰好 为 k k k 的数量。那么多了个什么东西呢?深度为 1 1 1 到 k − 1 k-1 k−1 的数量。不正是 f ( n , k − 1 ) f(n,k-1) f(n,k−1) 吗?作差即可。
还有一些小细节,稍微提一下:
- 每一种合法的家谱都是奇数个节点。
- f ( n , k ) f(n,k) f(n,k) 在模意义下可能小于 f ( n , k − 1 ) f(n,k-1) f(n,k−1) ,输出时应当处理。
代码
#include <cstdio>
const int M = 9901;
int dp[202][102];
int main(){
int n, k;
scanf("%d %d",&n,&k);
for(int j=1; j<=k; ++j){
dp[1][j] = 1;
for(int i=3; i<=n; i+=2)
for(int l=1; l<i-1; l+=2)
dp[i][j]=(dp[i][j]+dp[l][j-1]*dp[i-l-1][j-1])%M;
}
printf("%d\n",(dp[n][k]-dp[n][k-1]+M)%M);
return 0;
}