[知识点] 2.6 倍增思想

总目录 > 2 算法基础 > 2.6 倍增思想

前言

倍增通常和二分一起介绍,共同点在于——它们都能神奇地将原本复杂度为 n 的过程下降到 log n,对于大型数据而言,这种效率的提高是显而易见的。

子目录列表

1、二进制与倍增

2、例题

3、应用

 

2.6 倍增思想

1、二进制与倍增

众所周知,二进制与十进制转换关系:o = 2 ^ a * + 2 ^ b + ... + 2 ^ i,比如 77 = 2 ^ 6 + 2 ^ 3 + 2 ^ 2 + 2 ^ 0,则其二进制表示为 1001101。换言之,任何一个整数都可以由若干个系数为 1,x 为 2 的 2 次方幂的和组成。

所以尤记得小学时有个比较经典的问题:

如何用尽可能少的砝码称量出 [1, 30] 之间的所有重量?(天平左侧放物品右侧放砝码)

根据上述原理,则只需要 1, 2, 4, 8, 16 五个重量级的砝码即可,能够组成 [1, 30] 之间的任意数。

如果修改成 [1, 60] 呢?多一个 32 即可;

如果修改成 [1, 21647483647] 呢?则再加上 2 ^ 6, 2 ^ 7, ..., 2 ^ 30,总共也只需要 31 个砝码。

注意到,我们将这个看似巨大的数字,通过这个思路,很轻松地就得到了 log n 级别的一个结果。而倍增思想,字面意思就是翻倍,其实就是建立在二进制和十进制这个关系上的。

 

2、例题

给出一个长度为 n 的环和一个常数 k,每次可以从第 i 个点跳到第 (i + k) mod (n + 1) 个点,总共跳 m 次。第 i 个点的权值为 a[i],求 m 次跳跃的起点的权值之和 mod 1e9 + 7。

(原题面没有给出初始位置?)

强调一下数据范围:m <= 1e18,也就是说我们不可能对于每一次跳跃都记录位置。由于只需要知道 m 次跳跃的权值和,过程其实并不重要,那么就可以采用倍增的方式。

假设 n = 5, m = 29,将环拆成线性的。下图为跳跃图解:

选择在终点之前最远的跳跃方式:从第 1 个位置跳到第 9 个位置。

从第 9 个位置跳到第 13 个位置。

最后从第 13 个位置跳到第 14 个位置,图略。

所以从 1 到 14 的整个跳跃过程由 2 ^ 3 + 2 ^ 2 + 2 ^ 0 三步组成。也就是说,对于环上这 n 个位置,预处理出每一个位置向前跳 1, 2, 4, ... 次的位置,则必然能够到达 m。1e18 <= 2 ^ 64,至多倍增跳跃 64 次就够了,而预处理过程同样只需要 O(n log m) 的时间/空间复杂度

代码略。

 

3、应用

倍增思想最常见的应用:快速幂,LCA 和 RMQ 问题等等。

快速幂请参见:6.2 快速幂

倍增 LCA 请参见:<施工中>

RMQ 问题请参见:<施工中>

posted @ 2020-05-12 14:44  jinkun113  阅读(583)  评论(1编辑  收藏  举报