J. Counting Trees (树,卡特兰数)
题目
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 (树,卡特兰数)相关推荐
- 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 ...
- 11.05T2 线段树+卡特兰数
#3876 快速排序 描述 输入 输出 对于每个询问,输出一行三个整数,分别表示最大差距.最小差距和方案数. 样例输入[复制] 3 3 1 2 3 4 5 6 1 1 6 0 1 6 10 1 1 6 ...
- 【卡特兰数】【递推】【高精+压位】JZOJ·WZK打雪仗
题目大意: 有2n个人站在一个圈里,有n人要去其他n人那(两人连一线),线不能与其他线碰在一起,让你求方案数. 思路: 卡特兰数,因为位数大,高精压位走起 CodeCodeCode: #include ...
- 【JZOJ】【卡特兰数】【高精】WZK打雪仗
DescriptionDescriptionDescription 按顺序排成的一个有2n个点的圆,问有多少种方法,连接n条边(两个点之间相连),每个点只能连一条边,问有多少种方案使得n条边互不相交 ...
- [集训队作业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 ...
- 卡特兰数——Catalan数
卡特兰数是组合数学中一个常出现在各种计数问题中出现的数列.由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名. 卡塔兰数的一般项公式为 通常使用的递归式: h(n)=((4*n-2) ...
- Catalan number卡特兰数
背景知识介绍: 卡特兰数是离散数学中的一个重要数列,是很多生活场景的一个抽象,比如买早餐.买电影票等等.在很多大公司的笔试或者面试题中也常涉及到. 百度百科介绍 卡特兰数 卡特兰数是组合数 ...
- 【编程题练习】牛客-阿里:二叉树(卡特兰数)
小强现在有nn个节点,他想请你帮他计算出有多少种不同的二叉树满足节点个数为nn且树的高度不超过mm的方案.因为答案很大,所以答案需要模上1e9+7后输出. 树的高度: 定义为所有叶子到根路径上节点个数 ...
- Catalan数——卡特兰数
今天阿里淘宝笔试中碰到两道组合数学题,感觉非常亲切,但是笔试中失踪推导不出来 后来查了下,原来是Catalan数.悲剧啊,现在整理一下 Catalan数--卡特兰数] 一.Catalan数的定义令h( ...
最新文章
- 浅谈使用openwave测试的几个注意项
- 物联网行业网络解决方案_2021物联网趋势:有望从物联网传感器网络中受益的5大行业...
- (Java集合框架)集合框架概述和Collection常用功能及遍历
- 基于Windows 7旗舰版搭建WinCE6.0开发环境的过程
- FPGA开发全攻略—— 调试
- Python各种推导式(列表推导式,字典推导式,集合推导式,嵌套列表推导式)
- python发送文件_python:socket传输大文件
- 使用oracle/mysql/tidb由空格引发的血案解析
- Log4j2 Zero Day 漏洞 Apache Flink 应对指南
- 阿里云盘内测_阿里云盘 | 内测码分享 + 火速体验!
- add_subplot()--matplotlib
- Nod32的内网升级方案
- zend新建php项目,如何使用Zend Studio创建PHP项目
- 怎么利用微博进行营销?
- VC编程获取和修改环境变量,不重启系统即时生效
- win7计算机出现空白图标,Win7系统桌面图标显示异常变未知白色图标解决方法大全...
- 字母异位词(anagram)的不同复杂度实现
- 不要把精力浪费在“吃瓜”上
- Swap Adjacent Elements CodeForces - 920C
- 命令行导入 .dmp文件,亲测可行