题目

https://codeforces.com/gym/102501/problem/J

大意就是,规定一棵二叉树,每个节点的值都大于等于其父节点的值。给出一个中序遍历值序列,问有多少棵这样的树满足其中序遍历是这个。
节点数范围 1e6,节点值范围 1e6。

思路

  • 中序遍历,满足一棵子树映射到序列中一段区间。

  • 对于一个区间,若它代表一个子树,那么该子树的根就是区间内最小的值。

  • 若区间内有多个最小的值,那这些位置应该组成一个包含子树根的连通块,这些点分割出来的区间,分别代表下面的一棵子树。连通块有多种可能,不过一旦确定出这个连通块形态(即这几个点组成的树的形态),那么分割出的几棵子树位置就确定了。

  • 也就是说,变成了一个递归问题。对于子树 [L, R],取出其中最小的值,假设是 x[1], x[2], ..., x[k] ,那么答案就是递归求出分出来的 k+1 个区间的答案之积,再乘上满足中序遍历是 1, 2, …, k 的二叉树个数。

  • 乘上的这个数,其实就是卡特兰数 Cat[k]。考虑一棵二叉树的中序遍历其实对应出一种出入栈序列。

  • 卡特兰数可以看这个博客 https://blog.csdn.net/chenlong_cxy/article/details/113613203

代码

#include <bits/stdc++.h>
using namespace std;#define Ha 1000000007
#define MAXN 1000005
long long Cat[MAXN];
int n;
int a[MAXN];
int ST[MAXN][25];
vector<int> pos[MAXN];long long ksm(long long x, int k)
{long long ret=1;for (; k; k>>=1, x=x*x%Ha)if (k&1) ret = ret*x%Ha;return ret;
}int getMin(int L, int R)
{int k = R-L+1;int ret=a[L];int cur = L;for (int i=0; i<=20; i++) {if (k&(1<<i)) {ret = min(ret, ST[cur][i]);cur+=(1<<i);}}return ret;
}long long dfs(int L, int R)
{if (L>=R) return 1;int mn = getMin(L, R);long long ret=1, cnt=0;int lst=L, cur;auto pl = lower_bound(pos[mn].begin(), pos[mn].end(), L);while (pl!=pos[mn].end() && *pl<=R) {cnt++;cur = *pl;ret = ret * dfs(lst, cur-1) %Ha;lst = cur+1;pl++;}ret = ret * dfs(lst, R) %Ha;ret = ret * Cat[cnt] %Ha;return ret;
}void solve()
{scanf("%d", &n);Cat[0] = 1;for (int i=0; i<n; i++) Cat[i+1] = Cat[i]*(i*4+2)%Ha *ksm(i+2, Ha-2) %Ha;for (int i=1; i<=n; i++) {scanf("%d", &a[i]);ST[i][0] = a[i];pos[a[i]].push_back(i);}for (int j=1,jj=1; j<=20; j++,jj<<=1)for (int i=1; i+jj<=n; i++)ST[i][j] = min(ST[i][j-1], ST[i+jj][j-1]);long long ans = dfs(1, n);ans = (ans+Ha)%Ha;printf("%lld\n", ans);
}int main()
{solve();return 0;
}

J. Counting Trees (树,卡特兰数)相关推荐

  1. HDU 3240 Counting Binary Trees 数论-卡特兰数

    题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3240 卡特兰数递推公式h(i)=h(i-1)*(4*i-2)/(i+1) 如果直接算每一步,然后mo ...

  2. 11.05T2 线段树+卡特兰数

    #3876 快速排序 描述 输入 输出 对于每个询问,输出一行三个整数,分别表示最大差距.最小差距和方案数. 样例输入[复制] 3 3 1 2 3 4 5 6 1 1 6 0 1 6 10 1 1 6 ...

  3. 【卡特兰数】【递推】【高精+压位】JZOJ·WZK打雪仗

    题目大意: 有2n个人站在一个圈里,有n人要去其他n人那(两人连一线),线不能与其他线碰在一起,让你求方案数. 思路: 卡特兰数,因为位数大,高精压位走起 CodeCodeCode: #include ...

  4. 【JZOJ】【卡特兰数】【高精】WZK打雪仗

    DescriptionDescriptionDescription 按顺序排成的一个有2n个点的圆,问有多少种方法,连接n条边(两个点之间相连),每个点只能连一条边,问有多少种方案使得n条边互不相交 ...

  5. [集训队作业2018] count(笛卡尔树,生成函数,卡特兰数)

    传送门 什么情况下两序列同构 对于两序列A[1,n],B[1,n]A[1,n],B[1,n]A[1,n],B[1,n],设fA(1,n)=pa,fB(1,n)=pbf_A(1,n)=p_a,f_B(1 ...

  6. 卡特兰数——Catalan数

    卡特兰数是组合数学中一个常出现在各种计数问题中出现的数列.由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名. 卡塔兰数的一般项公式为  通常使用的递归式:  h(n)=((4*n-2) ...

  7. Catalan number卡特兰数

    背景知识介绍:   卡特兰数是离散数学中的一个重要数列,是很多生活场景的一个抽象,比如买早餐.买电影票等等.在很多大公司的笔试或者面试题中也常涉及到. 百度百科介绍   卡特兰数   卡特兰数是组合数 ...

  8. 【编程题练习】牛客-阿里:二叉树(卡特兰数)

    小强现在有nn个节点,他想请你帮他计算出有多少种不同的二叉树满足节点个数为nn且树的高度不超过mm的方案.因为答案很大,所以答案需要模上1e9+7后输出. 树的高度: 定义为所有叶子到根路径上节点个数 ...

  9. Catalan数——卡特兰数

    今天阿里淘宝笔试中碰到两道组合数学题,感觉非常亲切,但是笔试中失踪推导不出来 后来查了下,原来是Catalan数.悲剧啊,现在整理一下 Catalan数--卡特兰数] 一.Catalan数的定义令h( ...

最新文章

  1. 浅谈使用openwave测试的几个注意项
  2. 物联网行业网络解决方案_2021物联网趋势:有望从物联网传感器网络中受益的5大行业...
  3. (Java集合框架)集合框架概述和Collection常用功能及遍历
  4. 基于Windows 7旗舰版搭建WinCE6.0开发环境的过程
  5. FPGA开发全攻略—— 调试
  6. Python各种推导式(列表推导式,字典推导式,集合推导式,嵌套列表推导式)
  7. python发送文件_python:socket传输大文件
  8. 使用oracle/mysql/tidb由空格引发的血案解析
  9. Log4j2 Zero Day 漏洞 Apache Flink 应对指南
  10. 阿里云盘内测_阿里云盘 | 内测码分享 + 火速体验!
  11. add_subplot()--matplotlib
  12. Nod32的内网升级方案
  13. zend新建php项目,如何使用Zend Studio创建PHP项目
  14. 怎么利用微博进行营销?
  15. VC编程获取和修改环境变量,不重启系统即时生效
  16. win7计算机出现空白图标,Win7系统桌面图标显示异常变未知白色图标解决方法大全...
  17. 字母异位词(anagram)的不同复杂度实现
  18. 不要把精力浪费在“吃瓜”上
  19. Swap Adjacent Elements CodeForces - 920C
  20. 命令行导入 .dmp文件,亲测可行

热门文章

  1. LDAP是什么?LDAP与数据库有什么区别?
  2. win10系统如何连接打印机
  3. java读文件几种方式_JAVA读取文件的几种方式
  4. Linux下通过进程名称命令杀死进程
  5. MySQL字符串转时间、Oracle字符串转时间
  6. 两种方式导入excel
  7. 大型编程电视剧连载 | CSS知识点硬核整理归纳(一)
  8. thingworx学习总结(一)
  9. 《Photoshop图像合成专业技法(修订版)》—第1章1.4节精修头发
  10. 腾讯音乐-全民K歌iOS面经