浅谈快速幂算法

前言: 这份讲解只针对于C++新手,各位大佬请绕道,如有讲解错误的地方可留言给我,我会在第一时间回复并加以改正。

引入:快速幂的定义:顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

铺垫: 因为在代码实现中要用到位运算,没有学过位运算的读者我在这里简单讲解一下:
基本算术位运算:

and a n d ,&,如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。例:11&3 =1011 & 11(二进制数)=11(二进制数) = 3

or o r ,|,如果两个相应的二进制位只要有一个是1,结果就是1;否则为0。
例:11|2=1011 | 10(二进制数)=1011(二进制数) =11

not n o t ,~,这个在加法中用到
x-y = x + ~y + 1
所以~y = - y -1
比如 ~11 = -11 -1 = -12

异或 xor x o r ,^,两个相同的数会变成0,反之是1
例:11 ^ 3=1011 ^ 11 (二进制数)= 1000 (二进制数)=8

左移 :在二进制表示下把数字同时向左移动,地位以0填充,高位越界后舍弃。

1<<n=2n,n<<1=2n 1 << n = 2 n , n << 1 = 2 n

算术右移 :在二进制补码表示下把数字同时向右移动,高位以符号位填充,低位越界后舍弃。

n>>1=n/2.0 n >> 1 = ⌊ n / 2.0 ⌋

算术右移等于除以2向下除整, (3)>>1=2,3>>1=1 ( − 3 ) >> 1 = − 2 , 3 >> 1 = 1
值得一提的是,“整数/2”在C++中实现为“除以2向零取整”, (3)/2=1,3/2=1 ( − 3 ) / 2 = − 1 , 3 / 2 = 1 。请读者自己尝试使用C++编译器编译运行类似的语句,检查运算结果。

原理:比如我们要求 a a b 次方对 p p 取模的值,其中1<=a,b,p<= 109 10 9
相关题目:Poj1995 Raising Modulo Numbers(快速幂)

根据数学常识,每一个正整数可以唯一表示为若干指数不重复的2的次幂的和。也就是说,如果 b b 在二进制表示下有k 位,其中第 i(0<=i<k) i ( 0 <= i < k ) 位的数字是 ci c i

那么: b=ck2k1+ck12k2+...+c020 b = c k 2 k − 1 + c k − 1 2 k − 2 + . . . + c 0 2 0

于是: ab=ack12k1ack22k2...ac020 a b = a c k − 1 ∗ 2 k − 1 ∗ a c k − 2 ∗ 2 k − 2 ∗ . . . ∗ a c 0 ∗ 2 0

又因为: a2i=(a2i1)2 a 2 i = ( a 2 i − 1 ) 2

所以我们很容易通过 k k 次递推求出每个乘积项,当 ci=1 时,把该乘积项累积到答案中。b&1运算可以取出 b b 在二进制表示下的最低位,而 b>>1 运算可以舍去最低位,在递推的过程中将二者结合,就可以遍历 b b 在二进制表示下的所有数位 ci 。整个算法的时间复杂度为 O(log2b) O ( l o g 2 b )

代码实现:

int power(int a,int b,int p)
{
    int ans=1%p;
    while(b)
    {
        if(b&1)ans=(long long)ans*a%p;
        a=(long long)a*a%p;
        b>>=1;
    }
    return ans;
}

在上面的代码片段中,我们通过“右移(>>)”“与(&)”运算的结合,遍历了 b b 的二进制表示下的每一位。在循环到第 i 次时(从0开始计数),变量 a a 中存储的是 a2i ,若 b b 该位为1,则把此时的变量 b 累积到答案 ans a n s 中。

值得提醒的是,在C++语言中,两个数值执行算术运算时,以参与运算的最高数值类型作为基准,与保存结果的变量类型无关。换言之,虽然两个 32 32 位整数的乘积可能超过int类型的表示范围,但是 CPU C P U 只会用1个32位寄存器保存结果,造成我们常说的越界现象。因此,我们必须把其中一个数强制转换成64位整数类型 long long 参与运算,从而得到正确的结果。最终对 p p 取模以后,执行赋值操作时,该结果会被隐式转换成 int 存回 ans a n s 中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值