这题在网上找不到题解,硬写一下午终于写出来了……

题目:

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]代码(卡特兰数)的更多相关文章

  1. BZOJ2944 : [Poi2000]代码

    对于根,要让它的排名尽量小,也就是要让右子树的点数尽量多. 于是从大到小枚举右子树的点数,用Catalan数计算方案数,直到找到相应的右子树的点数为止. 此时根的排名已经确定,接下来要让左子树的代码的 ...

  2. 卡特兰数(Catalan)

    卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列.由以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)命名,其前几项为 : 1, 2, ...

  3. HDU 5673 Robot ——(卡特兰数)

    先推荐一个关于卡特兰数的博客:http://blog.csdn.net/hackbuteer1/article/details/7450250. 卡特兰数一个应用就是,卡特兰数的第n项表示,现在进栈和 ...

  4. HDU 1023 Traning Problem (2) 高精度卡特兰数

    Train Problem II Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Sub ...

  5. hdu 1023 卡特兰数+高精度

    Train Problem II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  6. HDU 1023 Train Problem II (卡特兰数,经典)

    题意: 给出一个数字n,假设火车从1~n的顺序分别进站,求有多少种出站序列. 思路: 卡特兰数的经典例子.n<101,用递推式解决.需要使用到大数.n=100时大概有200位以下. #inclu ...

  7. 2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd)

    题目链接 分析:打表以后就能发现时卡特兰数, 但是有除法取余. f[i] = f[i-1]*(4*i - 2)/(i+1); 看了一下网上的题解,照着题解写了下面的代码,不过还是不明白,为什么用扩展g ...

  8. poj 1095 Trees Made to Order 卡特兰数

    这题用到了卡特兰数,详情见:http://www.cnblogs.com/jackge/archive/2013/05/19/3086519.html 解体思路详见:http://blog.csdn. ...

  9. 【HDU 5370】 Tree Maker(卡特兰数+dp)

    Tree Maker Problem Description Tree Lover loves trees crazily. One day he invents an interesting gam ...

随机推荐

  1. BZOJ 4094 USACO 2013 Dec. Optimal Milking

    线段树 每个节点保存4个值,both表示左右端点都取,neither表示左右端点都不取,left表示只取左端点,right表示只取右端点. 维护的特殊姿势: $cur$的$both=max(ls.l+ ...

  2. Navicat premium连接Oracle报ORA-12541错误

    1:ORA-12541 原因:Oracle TNS监听服务没开 解决:

  3. 抽象类和接口有什么区别---https://blog.csdn.net/csdn_aiyang/article/details/71171886

    https://blog.csdn.net/csdn_aiyang/article/details/71171886 概念]   抽象类.具体类是相对的,并非绝对的.抽象是一种概念性名词,具体是一种可 ...

  4. HDU 1253 三维数组的图上找最短路

    题目大意: 从三维空间的(0,0,0)出发到(a-1,b-1,c-1),每移动一个都要时间加一,计算最短时间 根据六个方向,开个bfs,像spfa那样计算最短路径就行了,但是要1200多ms,也不知道 ...

  5. tmux使用入门

    tmux是Linux中窗口管理程序,适用于终端复用,尤其适合远程连接.最近,我正苦闷与ssh自动超时退出和broken pipe,决定投入tmux怀抱. 使用tmux最直接的好处,便是可以在一个远程连 ...

  6. java连接数据库(经常用)

    一.配置环境 1.首先下载sqlserver2008驱动文件,找到sqljdbc4.jar文件,将这个文件拷到C:\Program Files\Java\jdk1.8.0_121\jre\lib\ex ...

  7. IT领域的罗马帝国——微软公司

    微软公司从做软件开始,起步很小.但是盖茨确是一直深耕于战略布局,像一个棋局高手,每一步棋都是看了后面几步. 盖茨居然用9年的时间憋出一个win3.0,成功击败了apple. 而这9年拖住apple的居 ...

  8. Codeforces 303A(构造)

    题意:对0到(n-1)这n个数进行全排列.请找出三个全排列a.b.c,使得“a与b的对应元素的和”与“c的对应元素”对模n同余,无解输出-1.(n<=1e5) 分析:n为奇数有解,n为偶数无解 ...

  9. Windows下React Native开发01 -- Android开发环境搭建

    1.安装jdk 推荐将JDK的bin目录加入系统PATH环境变量(自己百度下怎么配置). 2.安装SDK 直接安装 Android Studio  推荐从AndroidDevTools下载.(也可以直 ...

  10. Redis: Useful commands

    SELECT X - Select database (the X must be int) CONFIG GET databases - Get databases number INFO keys ...