关键一:
![](https://img-blog.csdnimg.cn/img_convert/7fb4d1da8e7b5afaecad0093d1d49e10.png)
关键二:
![](https://img-blog.csdnimg.cn/img_convert/d6424a79897dd80443a92d56f1cd7e4c.png)
![](https://img-blog.csdnimg.cn/img_convert/4ac0f688dc11c1a6307ef6c7e6bb9aa1.png)
加油!
核心:***将指数(b),转化(看成)二进制进行处理
#include<bits/stdc++.h>
using namespace std;
long long b, a, p, k, ans = 1, c;
int main()
{
scanf("%lld%lld%lld", &b, &p, &k);
a = b; c = p;
while (p > 0)//快速幂
{
if (p % 2 != 0)
ans = ans * b % k;//如果p为单数,乘到ans里面去,然后取模
b = b * b % k;//每次运算都取模
p = p >> 1; //用位运算除2,可能会快一点
}
ans %= k;//多年前的代码了……今天突然发现有大佬告知代码错误,仔细一看是在p = 0时没有取模,加上这句话就可以了
printf("%lld^%lld mod %lld=%lld", a, c, k, ans);//输出
return 0;
}
1)如果将 aa 自乘一次,就会变成 a^2a2 。再把 a^2a2 自乘一次就会变成 a^4a4 。然后是 a^8a8…… 自乘 nn 次的结果是 a^{2^{n}}a2n 。对吧……
(2)a^xa^y = a^{x+y}axay=ax+y,这个容易。
(3)将 bb 转化为二进制观看一下:
比如 b = (11)_{10}b=(11)10 就是 (1011)_{2}(1011)2 。从左到右,这些 11 分别代表十进制的 8,2,18,2,1。可以说 a^{11} = a^8 × a^2 × a^1a11=a8×a2×a1。
为什么要这样表示?因为在快速幂的过程中,我们会把 aa 自乘为 a^2a2,然后 a^2a2 自乘为 a^4a4……像上面第一条说的。
过程会是这样:
(好长,可以不看,如果要阅读下面的模拟过程的话,要慢慢地看噢)
·假设我们拿到了 aa,并且 b = 11b=11。想求 a^{11}a11,但是又不想乘11次,有点慢。
·以电脑视角稍稍观察一下 b = 11b=11,二进制下是 b = 1011b=1011。
·制作一个 basebase。现在 base = abase=a,表示的是,a^1 = aa1=a。待会 basebase 会变的。
·制作一个 ansans,初值 11,准备用来做答案。
while(b > 0)
{
·循环一。看,bb(二进制)的最后一位是 11 吗? 是的。这代表 a^{11} = a^8 × a^2 × a^1a11=a8×a2×a1 中的“ × a^1×a1 ”存在。所以 ans *= baseans∗=base。
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。
挺巧妙的,并且很快。)*/
·然后 basebase 努力上升,他通过自乘一次,使自己变成 a^2a2。
base *= base;
同时
b >>= 1;
它把(二进制的)自己每一位都往右移动了。原来的最后第二位,变成了最后第一位!b = (101)_2b=(101)2。
}
·循环二,再看看 bb,最后一位还是 11。这说明有“ × a^2×a2 ”,ans *= baseans∗=base。
·basebase 继续努力,通过 base *= basebase∗=base 让自己变成了 a^4a4。然后 bb 也右移 一位。b = 10b=10。
·循环三,可是 bb 的最后一位不再是 11 了,说明不存在“ × a^4×a4 ”。basebase 自我升华,达到了 a^8a8。且 b >>= 1b>>=1。这一步中,答案没有增加,可是毕竟 b > 0b>0,还有希望。
·循环四,bb 的最后一位是 11,这说明“ ×a^8×a8 ”的存在。ans *= baseans∗=base。由于 bb 再右移一位就是 00 了,循环结束。
总的来说,如果 bb 在二进制上的某一位是 11,我们就把答案乘上对应的 a^{2^{n}}a2n。不懂的话,请结合代码理解~