1.2 递推与递归

递归实现指数型枚举

算法:递归。

一道板子题,用一个 \(vector\) 维护选的数即可,递归时递归选这个数和不选这个数即可。

当然我们有另外一个写法,用一个 \(n\) 位二进制数的每一位表示每个数选或不选,输出时如果这一位是 \(1\) 就代表选,要输出。

递归实现组合型枚举

算法:递归。

和上一道题差不多,仍然还是看这个数选或不选,只不过要看一下是否出现:

  • 当前选的数已经超过 \(m\) 个。

  • 即使后面的数都选也凑不够 \(m\) 个。

然后就排除了不合法的解,剩下的都是合法的解。

递归实现排列型枚举

算法:递归。

仍然是比较简单的一道题,考虑用一个数组记录每个数是否已经用过,没有的话考虑这一位用这个数,并标记一下即可。

当然,我们可以使用自带的 next_permutation 函数,这样更加方便。

费解的开关

算法:二进制枚举。

考虑一个暴力,我们枚举每一位看是否要操作。然后操作每一位。

但是你会发现,这样枚举加上操作,显然是会超时的,所以我们要考虑优化。

如果我们只枚举第 \(1\) 行呢?那么我们每次只需要枚举 \(2^5\) 次即可。而对于后面的行,如果第 \(1\) 行操作完了,我们看第 \(2\) 行有哪些不合法,操作这个格子即可,这样我们的效率就是可以接受的了。

所以这样以此类推,枚举第 \(1\) 行的操作,然后依次推出下一行的操作,记录最小操作次数即可。

奇怪的汉诺塔

算法:递推。

做这道题,首先要知道在 \(3\) 塔的情况下的最小步数,这里直接给出这个广为人知的结论:设 \(d_n\) 表示 \(n\)\(3\) 塔的最小步数,则 \(d_n=2\times d_{n-1}+1,d_0=0\)

接下来我们要想的问题就变成了,如何把 \(3\) 塔情况推广到 \(4\) 塔情况?

我们首先可以进行转化:先把 \(i\) 个盘子在 \(4\) 塔情况下移动到第二个柱子,然后我们可以假定第二个柱子不存在,把剩下的盘子在 \(3\) 塔情况下移动到最后一个柱子,再把刚才放到第二个柱子上的盘子移动到最后一个柱子上。

我们形式化的说,设 \(f_n\) 表示 \(n\)\(4\) 塔的最小步数,所以有:\(f_n=\min(2\times f_i+d_{n-i})\),于是递推一下就做完了。

约数之和

算法:数学,分治。

我们在这里提及两个方法,数学法和分治法,其中主要介绍一下分治法。

数学法比较好说,我们找出这个数的所有质因数 \(p_1,p_2,\cdots,p_k\)。只需要计算 \((1+p_1+\cdots+p_1^{k_1})\times \cdots \times (1+p_k+\cdots+p_k^{c_k})\)

我们使用等比数列求和公式就可以比较轻松的计算出每个式子,最后相乘即可。

你以为就这么简单?这样做有一个坑点,因为等比数列的公式是要除以 \(p_i-1\) 的,这个东西可能不能转化为逆元计算,所以在不能转化为逆元时需要特判,直接把答案乘上 \(c_i+1\) 即可。

下面说一下分治法,我们考虑用数学计算的那个式子怎么用分治法计算,考虑拆一下式子:

\(1+p+p^2+\cdots+p^{k-1}=sum(p,k)\)

第一种情况,k为偶数:

\(sum(p,k)=1+p^1+\cdots+p^{\frac{k}{2}-1}+p^{\frac{k}{2}}+\cdots+p^k-1\)

\(=1+p+\cdots+p^{\frac{k}{2}-1}+p^{\frac{k}{2}}\times (1+p+\cdots+p^{\frac{k}{2}-1})\)

\(=(p^{\frac{k}{2}}+1)\times (1+p+\cdots+p^{\frac{k}{2}-1})\)

\(=(p^{\frac{k}{2}}+1)\times sum(p,\frac{k}{2})\)

否则如果 \(k\) 为奇数,转化成 \(sum(p,k-1)+p^{k-1}\) 即可。

与是这样的时间复杂度我们就可以接受了,不过在计算形如 \(p^k\) 的式子需要时用快速幂,否则仍然会超时。

分形之城

算法:分形。

我们首先观察一下等级 \(1\) 到等级 \(2\) 的转移规律,规律相对来说是显然的,只有翻转和旋转的操作。

为了方便表示,设 \(n\) 为当前级别,平移长度 \(len=2^{n-1}\)

我们这里写一下坐标的变换:

左上角:\((x,y)\rightarrow(y,x)\)

右上角:\((x,y)\rightarrow(x,y+len)\)

右下角:\((x,y)\rightarrow(x+len,y+len)\)

左下角:\((x,y)\rightarrow(len\times 2-y-1,len-x-1)\)

这里可以发现,\(n-1\) 级别图共有 \(cnt=2^{2\times n-2}\) 个城市,而 \(m\) 号城市所在块的编号为 \(\lfloor\dfrac{m}{cnt}\rfloor\)(\(0\) 为左上,\(1\) 为右上,\(2\) 为右下,\(3\) 为左下)。设 \(m\) 号城市在 \(n\) 级城市中,那么它在 \(n-1\) 级城市中的编号为 \(idx=m\bmod cnt\)

所以我们在递归时记录当前城市级别及其编号还有所属块,即可一步步确定该城市在每一级城市中的坐标,把所有的坐标合到一起就可以算出来两个城市的坐标,直接求距离即可。

posted @ 2024-07-11 07:36  zxh923  阅读(2)  评论(0编辑  收藏  举报