【BZOJ2944】[Poi2000]代码(卡特兰数)
这题在网上找不到题解,硬写一下午终于写出来了……
题目:
BZOJ2944
分析:
首先明确:
比较两棵节点数相同的二叉树时,根节点是第一关键字,左子树是第二关键字,右子树是第三关键字;
然后我们分析一下题目中那个4个节点,14种代码的例子
左子树大小\(sl\) | 右子树大小\(sr\) | 根节点 | 对应名次 | 对应代码数量 | \(C_{sl}*C_{sr}\) |
---|---|---|---|---|---|
0 | 3 | a | 1~5 | 5 (abcd 、abdc、 acbd、 adbc、 adcb) | \(1*5=5\) |
1 | 2 | b | 6~7 | 2 (bacd、 badc) | \(1*2=2\) |
2 | 1 | c | 8~9 | 2 (cabd、 cbad) | \(2*1=2\) |
3 | 0 | d | 10~14 | 5 (dabc、 dacb、 dbac、 dcab、 dcba) | \(5*1=5\) |
(由于博客园的Markdown似乎不支持表格,此图截自我的CSDN博客)
(先不管最后一列)我们发现左子树大小决定了根节点的字母,并将这14种二叉树形态分成了长度为5、2、2、5的四“段”。因此,我们知道要求第多少名,就可以根据它在哪一段求出左子树的大小(比如样例中的第11名在第4段,因此左子树大小为3,代码一定以'd'开头)。并且这个过程可以递归下去,求出树的形态。代码如下
void dfs(ll n, int k, int tmp)
{
int sizel = 0, sizer = k - 1;
/*算出左子树的大小*/
printf("%c", (char)(sizel + tmp + 'a'));
if (sizel > 0)
dfs(/*左子树的名次*/, sizel, tmp);
if (sizer > 0)
dfs(/*右子树的名次*/, sizer, tmp + sizel + 1);
}
有一个结论,如果用\(C_n\)表示\(Catalan\)数的第n项,则\(n\)个结点的二叉树有\(C_n\)种不同的形态
(证明见Catalan number - Wikipedia,相关公式推导见【知识总结】卡特兰数 (Catalan Number) 公式的推导)
那么当根节点的字母固定,左右子树大小随之固定,以该字母开头的代码的数量就是\(C_{sl}*C_{sr}\),也就是上表最后一列。
根据这个性质,可以暴力算出根节点的字母和左右子树的大小,代码如下
while (n)
{
if (n > Catalan[sizel] * Catalan[sizer])
{
n -= Catalan[sizel] * Catalan[sizer];
sizel++, sizer--;
}
else
break;
}
这段代码执行后,\(n\)就是当根节点固定时该代码的排序(比如样例中dacb是以'd'开头的第二个,此时\(n=2\))
此时的排序是以左子树为第一关键字,右子树为第二关键字的。可以想象成一个两位数,个位满\(C_{sr}\)向十位进一。所以此时所求左子树在\(C_{sl}\)个左子树中的排名是\(\lceil \frac{n}{C_{sr}}\rceil\),所求右子树在\(C_{sr}\)个右子树中的排名是\(n\ mod\ C_{sr}\)(注意特判\(0\)的情况)
代码:
注意不是每一棵子树所代表的字母集合都是从'a'开始的,所以要有\(tmp\)变量
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
namespace zyt
{
typedef long long ll;
ll Catalan[20];
void dfs(ll n, int k, int tmp)
{
int sizel = 0, sizer = k - 1;
while (n)
{
if (n > Catalan[sizel] * Catalan[sizer])
{
n -= Catalan[sizel] * Catalan[sizer];
sizel++, sizer--;
}
else
break;
}
printf("%c", (char)(sizel + tmp + 'a'));
if (sizel > 0)
dfs(ceil((double)n / Catalan[sizer]), sizel, tmp);
if (sizer > 0)
{
int x = n % Catalan[sizer];
dfs(x ? x : Catalan[sizer], sizer, tmp + sizel + 1);
}
}
void work()
{
ll n;
int k;
scanf("%lld%d", &n, &k);
Catalan[0] = 1;
for (int i = 1; i <= k; i++)
Catalan[i] = Catalan[i - 1] * (4 * i - 2) / (i + 1);
dfs(n, k, 0);
}
}
int main()
{
zyt::work();
return 0;
}
【BZOJ2944】[Poi2000]代码(卡特兰数)的更多相关文章
- BZOJ2944 : [Poi2000]代码
对于根,要让它的排名尽量小,也就是要让右子树的点数尽量多. 于是从大到小枚举右子树的点数,用Catalan数计算方案数,直到找到相应的右子树的点数为止. 此时根的排名已经确定,接下来要让左子树的代码的 ...
- 卡特兰数(Catalan)
卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列.由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名,其前几项为 : 1, 2, ...
- HDU 5673 Robot ——(卡特兰数)
先推荐一个关于卡特兰数的博客:http://blog.csdn.net/hackbuteer1/article/details/7450250. 卡特兰数一个应用就是,卡特兰数的第n项表示,现在进栈和 ...
- HDU 1023 Traning Problem (2) 高精度卡特兰数
Train Problem II Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Sub ...
- hdu 1023 卡特兰数+高精度
Train Problem II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- HDU 1023 Train Problem II (卡特兰数,经典)
题意: 给出一个数字n,假设火车从1~n的顺序分别进站,求有多少种出站序列. 思路: 卡特兰数的经典例子.n<101,用递推式解决.需要使用到大数.n=100时大概有200位以下. #inclu ...
- 2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd)
题目链接 分析:打表以后就能发现时卡特兰数, 但是有除法取余. f[i] = f[i-1]*(4*i - 2)/(i+1); 看了一下网上的题解,照着题解写了下面的代码,不过还是不明白,为什么用扩展g ...
- poj 1095 Trees Made to Order 卡特兰数
这题用到了卡特兰数,详情见:http://www.cnblogs.com/jackge/archive/2013/05/19/3086519.html 解体思路详见:http://blog.csdn. ...
- 【HDU 5370】 Tree Maker(卡特兰数+dp)
Tree Maker Problem Description Tree Lover loves trees crazily. One day he invents an interesting gam ...
随机推荐
- Wind rotor states
test test Table of Contents 1. Wind rotor states 1.1. Turbulent Wake State 1.2. Vortex Ring State 1. ...
- 用记事本写第一个Java程序
public class Welcome{ public static void main(String[] args){ System.out.println("我是尚学堂的高淇,很高兴认 ...
- Git——跟踪或取消跟踪文件
在Git是用过程中,可能遇到以下情况: 1.被跟踪文件里面有不想跟踪的文件. 2.每次用git status查看状态时总是列出未被跟踪的文件. 解决方法: 1.当被跟踪的文件里面有不想跟踪的文件时,使 ...
- mariadb-10GTID复制及多源复制
---本文大纲 一.什么是GTID 二.应用场景 三.多线程复制说明 四.实现过程 五.多源复制原理 六.实现过程 ---------------------------------- 一.什么是GI ...
- free web rich code eidtor
free web rich code eidtor https://i.cnblogs.com/Preferences.aspx tiny code-editor https://apps.tiny. ...
- 【BZOJ3790】神奇项链(manacher,树状数组)
题意: 思路:生成一些回文拼起来使生成的段数最小 显然存在一种最优的方案,使生成的那些回文是目标串的极长回文子串 求出对于每个位置的最长回文子串,问题就转化成了: 给定一些已知起始和终止位置的线段,求 ...
- I - 最少拦截系统
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; ],su ...
- MYSQL的一些常用函数
#数学函数 SELECT ABS(-8);#绝对值SELECT CEILING(9.8);#查询大于等于给定数值的最小整数SELECT FLOOR(9.8);#查询小于等于给定数值的最大整数SELEC ...
- Container/Injection 为什么会出现容器的思路,以后会有什么的趋势,未来是怎样的
一.为什么会出现容器的思路? 容器概念始于 1979 年提出的 UNIX chroot,它是一个 UNIX 操作系统的系统调用,将一个进程及其子进程的根目录改变到文件系统中的一个新位置,让这些进程只能 ...
- C#保留2位小数几种场景总结 游标遍历所有数据库循环执行修改数据库的sql命令 原生js轮盘抽奖实例分析(幸运大转盘抽奖) javascript中的typeof和类型判断
C#保留2位小数几种场景总结 场景1: C#保留2位小数,.ToString("f2")确实可以,但是如果这个数字本来就小数点后面三位比如1.253,那么转化之后就会变成1.2 ...