LA 4847 binary search tree

这篇博客探讨了如何利用动态规划(也称为递推)来处理二叉搜索树的问题。首先,建立一个二叉搜索树,接着采用记忆化搜索,每个节点存储子树的大小和种类数。节点的种类数可以通过子树大小的交叉排列方案数来计算,这个方案数可以通过预处理得到。博客中提到,对于给定的输入排列,计算出产生相同二叉搜索树的排列总数,并取模999991输出结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A binary search tree is a binary tree. It may be empty. If it is not
empty, it satisfies the following properties: (1) Every node has a
key, and no two nodes have the same key. (2) The keys in a nonempty
left subtree must be smaller than the key in the root of the subtree.
(3) The keys in a nonempty right subtree must be larger than the key
in the root of the subtree. (4) The left and right subtrees are also
binary search trees. Sample binary search trees are shown in Figure 1.
Figure 1. binary search trees To search for a node with a key k in a
binary search tree T , we begin at the root. If T is empty, T contains
no keys and the search is unsuccessful. Otherwise, we compare k with
the key in root. If k equals root’s key, then the search terminates
successfully. If k is less than root’s key, we search the left subtree
of the root. If k is larger than root’s key, we search the right
subtree of the root. In the same way, we can proceed the search in the
left or right subree of T . To insert a new key k into a binary search
tree T where k is different from those of existing keys in T , we
first search the tree T . The search will be unsuccessful, then we
insert the key at the point the search terminated. For instance, to
insert a key 80 into the Figure 1(a), we first search the tree for 80.
This search terminates unsuccessfully, and the last node examined has
key 40. We insert a new node containing 80 as the right child of the
node. The resulting search tree is shown in Figure 1(b). In this
problem, we consider binary search trees with N keys 1 ; 2 ;:::;N .
For a permutation a 1 a 2 :::a N of f 1 ; 2 ;:::;N g , inserting a 1 a
2 :::a N successively into an initially empty binary search tree will
produce a binary search tree. For instance, the permutation 2 1 4 3 5
will produce the tree in Figure 1(c). Also, 2 4 3 1 5 will produce the
same tree. Actually, 8 permutations among all possible permutations of
1, 2, 3, 4, 5 will produce the same tree to the tree in Figure 1(c).
We are interested in finding the number of permutations of f 1 ; 2
;:::;N g such that all those permu- tations produce a binary search
tree identical to the tree produced by a given permutation P . Given N
and P , you are to write a program that calculates the number of
permutations satisfying the above condition. Input Your program is to
read from standard input. The input consists of T test cases. The
number of test cases T is given in the first line. Each test case
starts with a line containing an integer N representing the number of
keys, 1 N 20 . In the next line, a permutation of length N is
given. There is a single space between the integers representing keys
in the permutation. Output Your program is to write to standard
output. Print exactly one line for each test case as follows: Let B be
the number of permutations that produce the binary search tree
identical to the tree produced by the input permutation. Print B mod 9
; 999 ; 991 for each test case. For example, if B
= 20 ; 000 ; 000 , the output should be 18 for that test case. The following shows sample input and output for three test cases.

动态规划【你也可以叫递推】。
先建一棵树。
然后记忆化搜索,每个点维护两个值,子树大小size和种类数ans。
p.ans=l.ans×r.ans×cnt(l.size,r.size)。
其中cnt(x,y)表示把长度分别为x和y的序列相互交叉排列得到的方案数,可以通过预处理求出。

#include<cstdio>
#include<cstring>
const long long md=9999991;
struct node
{
    int x,l,r,size;
    long long ans;
}t[25];
int size,root;
long long cnt[25][25];
void pre()
{
    int i,j,k;
    for (i=1;i<=23;i++)
      cnt[0][i]=cnt[i][0]=1,cnt[1][i]=cnt[i][1]=i+1;
    for (i=2;i<=23;i++)
      for (j=2;j<=23;j++)
        for (k=0;k<=j;k++)
          cnt[i][j]=(cnt[i][j]+cnt[i-1][j-k])%md;
}
void up(int p)
{
    t[p].size=t[t[p].l].size+t[t[p].r].size+1;
    if (t[p].l*t[p].r==0)
      t[p].ans=t[t[p].l+t[p].r].ans;
    else
      t[p].ans=(t[t[p].l].ans*t[t[p].r].ans*cnt[t[t[p].l].size][t[t[p].r].size])%md;
}
void ins(int &p,int x)
{
    if (p==0)
    {
        p=++size;
        t[p].x=x;
        return;
    }
    if (x<t[p].x) ins(t[p].l,x);
    else ins(t[p].r,x);
}
void cal(int p)
{
    if (p==0) return;
    if (t[p].l==0&&t[p].r==0)
    {
        t[p].size=t[p].ans=1;
        return;
    }
    cal(t[p].l);
    cal(t[p].r);
    up(p);
}
int main()
{
    int i,j,k,l,m,n,p,q,x,y,z,T;
    scanf("%d",&T);
    pre();
    while (T--)
    {
        memset(t,0,sizeof(t));
        size=root=0;
        scanf("%d",&n);
        for (i=1;i<=n;i++)
          scanf("%d",&x),ins(root,x);
        cal(root);
        printf("%lld\n",t[root].ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值