[复习资料][随想]如何枚举一个排列
[随想]如何枚举一个排列
感觉最近博客里啥也没有写了,赶紧来写个东西让博客看起来没有那么冷清(大雾
有这样一类问题,需要你去枚举大小为 \(n\) 的全排列,此时可以从下面几种方法去考虑:
- “直接枚举”。枚举每个位置选的是哪个数,或者枚举每个数放在哪个位置。
- “插入法枚举”。从左到右考虑每个位置选择的数在前缀的排名,类似在前面排好序的所有数中插入一个数,或者从小到大枚举每个数插在的相对位置。
- “状压枚举”。从左到右考虑每个位置,状压已经使用过的所有数。
- “置换枚举/划分数枚举”。将排列看做是一个置换,此时可以通过枚举划分数来枚举每个置换的大小,如果已经知道每个置换的大小分别是 \(a_1,a_2,\dots,a_k(\sum_{i=1}^ka_i=n)\) ,大小为 \(i\) 的置换个数为 \(b_i\) ,那么置换大小恰好这么多的排列个数是 \(\frac{n!}{\prod_{i=1}^ka_i\prod_{i=1}^nb_i!}\) 。
- “笛卡尔树枚举”。枚举笛卡尔树上面每个点的父亲编号,或者枚举笛卡尔树上每个点的儿子编号,需要注意的是儿子是有顺序的(有左右儿子之分)。
- “多叉树枚举”。对于一个排列 \(p\) ,如果规定 \(i\) 的父亲节点是 \(\max \{j\mid j<i\land p_j<p_i\}\bigcap \{0\}\) ,并且规定一个节点的儿子的顺序是按位置从小到大,那么就可以给这个排列构建出一棵儿子有顺序根为 \(0\) 的树,并且不难发现这样的树和排列是一一对应的,这棵树按儿子顺序 dfs 得到的 dfs 序恰好是排列 \(p\) ,并且这棵树满足一个点的编号要比排名比它小的兄弟和它的父亲大。
对于上述的第 4 点的排列个数的解释,首先假设置换是有标号的,那么方案数就是:
\[{n\choose a_1,a_2,\dots,a_k}\prod_{i=1}^k(a_i-1)!=\frac{n!}{\prod_{i=1}^ka_i}
\]
但是置换是没有标号的,所以方案数是:
\[\frac{n!}{\prod_{i=1}^ka_i\prod_{i=1}^nb_i!}
\]
对于第 6 点,构建出来的树其实还有一种构造方法,就是对于每个 \(i(1\le i\le n)\) ,给 \(i\) 在 \([0,i-1]\) 中选择一个父亲,并且规定儿子顺序(这里儿子顺序是按编号从大到小)后得到的树,并且构建出来得到的树“多叉转二叉”后其实就是笛卡尔树。
当然可能还会有其他枚举方法,我见到了大概(?)会放上来。