1 条题解
-
0
自动搬运
来自洛谷,原作者为

学委
希望以后某时候还能来写题!搬运于
2025-08-24 21:22:39,当前版本为作者最后更新于2018-07-02 13:02:22,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
2018-8-28 更新
听说有这么一种算法能够
让计算机很快地求出
暴力相乘的话,电脑要计算 次。用快速幂,计算次数在 级别,很实用。
原理 I
(1)如果将 自乘一次,就会变成 。再把 自乘一次就会变成 。然后是 …… 自乘 次的结果是 。对吧……
(2),这个容易。
(3)将 转化为二进制观看一下:
比如 就是 。从左到右,这些 分别代表十进制的 。可以说 。
为什么要这样表示?因为在快速幂的过程中,我们会把 自乘为 ,然后 自乘为 ……像上面第一条说的。
过程会是这样:
(好长,可以不看,如果要阅读下面的模拟过程的话,要慢慢地看噢)
·假设我们拿到了 ,并且 。想求 ,但是又不想乘11次,有点慢。
·以电脑视角稍稍观察一下 ,二进制下是 。
·制作一个 。现在 ,表示的是,。待会 会变的。
·制作一个 ,初值 ,准备用来做答案。
while(b > 0) {·循环一。看,(二进制)的最后一位是 吗? 是的。这代表 中的“ ”存在。所以 。
if(b & 1) ans *= base; /*关于 b & 1: “&”美名曰“按位与”。 x & y 是二进制 x 和 y 的每一位分别进行“与运算”的结果。 与运算,即两者都为 1 时才会返回 1,否则返回 0。 那么 b & 1 二进制 b = 1011 1 = 0001 b&1 = 0001 因为 1(二进制)的前面几位全部都是 0, 所以只有 b 二进制最后一位是 1 时,b & 1 才会返回 1。 挺巧妙的,并且很快。)*/·然后 努力上升,他通过自乘一次,使自己变成 。
base *= base;同时
b >>= 1;它把(二进制的)自己每一位都往右移动了。原来的最后第二位,变成了最后第一位!。
}
·循环二,再看看 ,最后一位还是 。这说明有“ ”,。
· 继续努力,通过 让自己变成了 。然后 也右移 一位。。
·循环三,可是 的最后一位不再是 了,说明不存在“ ”。 自我升华,达到了 。且 。这一步中,答案没有增加,可是毕竟 ,还有希望。
·循环四, 的最后一位是 ,这说明“ ”的存在。。由于 再右移一位就是 了,循环结束。
总的来说,如果 在二进制上的某一位是 ,我们就把答案乘上对应的 。不懂的话,请结合代码理解~
实现
int quickPower(int a, int b)//是求a的b次方 { int ans = 1, base = a;//ans为答案,base为a^(2^n) while(b > 0)//b是一个变化的二进制数,如果还没有用完 { if(b & 1)//&是位运算,b&1表示b在二进制下最后一位是不是1,如果是: ans *= base;//把ans乘上对应的a^(2^n) base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1)) b >>= 1;//位运算,b右移一位,如101变成10(把最右边的1移掉了),10010变成1001。现在b在二进制下最后一位是刚刚的倒数第二位。结合上面b & 1食用更佳 } return ans; }原理 II
没错快速幂有很多种理解方式。
这是2017年NOIP普及组的完善程序第1题,这里提示的思路和上面不一样。

从头开始。若当前 为偶数,咱们不着急,只需把 自乘,然后 (即考虑下一层,下几层会帮我们乘上 的)。
若当前 为奇数,说明 中前面那个 的存在,。然后继续考虑下一层(下几层会帮我们乘上 的)。注意,这里的 不是指题目开始给出的 ,而是当前层的 应有的值,这跟上面的 是一样的。
也是稍稍模拟一下比较好理解。
·假设我们拿到了 ,并且 。想求 。
·第一层循环。,一个奇数。将 分解为 来看。本层只需把 。那后面的呢?我们到下一层再搞定。下几层的总目标是让 ,也就是让 。来到下一层的方法是 且 。
·第二层循环几乎独立于第一层存在。,一个奇数。将 分解为 来看。本层只需把 。那后面的呢?我们到下一层再搞定。下几层的总目标是让 ,也就是让 。于是 且 。
·第三层循环,,不是奇数,不着急,只把 当作 。下几层的总目标是让 。于是 ,。
·第四层循环,,是奇数。这时候已经不用看成什么分解了, 就可完成总目标。 为 。结束循环。
代码和上面一样。因为 与 等效。 与 等效。

取余运算
快速幂经常要结合取余运算。这里也讲一点。
取余运算有一些好用的性质,包括:
证明都很简单,如果要说服自己的话拿起笔试试吧。可设 ……
于是快速幂过程中可以
while(b > 0) { if(b & 1) { ans *= base; ans %= m; } base *= base; base %= m; b >>= 1; }能保证这样下来最后的结果与“先乘到最后,再取余”的结果一样。
- 1
信息
- ID
- 227
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者