A binary search tree (BST) can be defined as a binary tree with the following properties:
The left subtree of a node contains only nodes with keys less than the node’s key;
The right subtree of a node contains only nodes with keys greater than the node’s key;
Both the left and right subtrees are also binary search trees.
There exists different insertion sequences when we try to build a binary search tree. As for the binary search tree shown below,
a valid insertion sequence can be 3 2 1 4 6 5
, or 3 2 4 1 6 5
, but cannot be 3 2 4 5 6 1.
Now you are given the pre-order traversal sequence of a binary search tree. Please write a program to calculate the total count of insertion sequences of this tree. Since the total can be very large, you should output the result modulo 1000000007 (10^9+7) .
Input Specification:
Each input file contains one test case. Each test case consists of two lines. In the first line, an integer N is given, denoting the count of elements in the binary search tree; and the second line gives the pre-order traversal sequence of the tree, in which numbers are separated by a space.
Output Specification:
Output the total count of insertion sequences in a line.
Sample Input:
6
3 2 1 4 6 5
Sample Output:
10
思路:
问有多少种有效插入序列,对于每一个结点来说,下一个插入的结点可以是左孩子也可以是右孩子,这并不会影响最终树的形态,所以在每一层上左右孩子的插入顺序是可以任选的,这个规律将递归地进行下去。
因此这道题的基本思路其实很简单,最笨的方法是按照输入序列建一棵树,然后对于每一个结点而言,它可以产生的不同的插入序列就是一个组合数,即在剩下的所有结点中任选左子树结点总数个结点(右子树也可以,因为是组合数),这个组合数就是当前这个结点按照上述任选左右孩子的规律所产生的不同插入顺序的数目。最后将每个结点的这个组合数累乘,就是这整棵树的有效序列的个数。
要注意的是题目的大数据测试样例如果单纯按照组合数累乘最后结果会溢出long long所能表达的最大值,因此每次运算组合数以及累乘的过程都要用到逆元数,逆元数可以用来处理大数。
有关逆元数可以参考博客
https://blog.csdn.net/bestsort/article/details/81132982
源码:
#include<stdio.h>
#include<stdlib.h>
#define MODULO 1000000007
typedef struct TreeNode *Tree;
typedef long long LL;
struct TreeNode {
Tree left;
Tree right;
int value;
int l, r;
};
//此处逆元函数参考CSDN博客,https://blog.csdn.net/bestsort/article/details/81132982
// 快速幂求逆元
LL pow_mod(LL a, LL b, LL p) {
//a的b次方求余p
LL ret = 1;
while (b) {
if (b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
//费马求a关于b的逆元
LL Fermat(LL a, LL p) {
return pow_mod(a, p - 2, p);
}
//递归建树,并且动态更新每个树结点的左右子树高度
Tree insertTree(Tree T, int value) {
if (!T) {
T = (Tree) malloc(sizeof(struct TreeNode));
T->right = T->left = NULL;
T->value = value;
T->l = 0;
T->r = 0;
} else {
if (value > T->value) {
T->r++;
T->right = insertTree(T->right, value);
} else {
T->l++;
T->left = insertTree(T->left, value);
}
}
return T;
}
//求组合数
long long getC(long long m, long long n) {
long long i;
long long sum = 1;
for (i = 0; i < m; i++) {
sum *= (n - i);
sum %= MODULO;
}
for (i = 2; i <= m; ++i) {
sum *= Fermat(i, MODULO);//每次乘一次逆元数都要mod
sum %= MODULO;
}
return sum;
}
//组合数累乘
long long preAndMultiply(Tree T) {
if (!T)return 1;
//每次都要mod,防止溢出
int C = getC(T->l, T->l + T->r) % MODULO;
return (C * preAndMultiply(T->left) % MODULO) * preAndMultiply(T->right) % MODULO;
}
int main() {
int N;
scanf("%d", &N);
int i;
Tree T = NULL;
for (i = 0; i < N; i++) {
int value;
scanf("%d", &value);
T = insertTree(T, value);
}
long long method = preAndMultiply(T);
printf("%lld", method);
return 0;
}