01 快速幂 & 龟速乘(附带实现代码) 算法总结记录

467 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

快速幂

快速幂用于解决的问题

在我们的学习语法的时候,比如我们求一个2的十次方的数字,我们可以采用循环一下就是枚举一下循环从1~10,这样我们就可以求出我们想要的答案,当次方为一千,一万,十万,我们这个方法都可以做,但是当我们乘上一个上亿级的次方,我们这样的方法就行不通了,我们知道c++在运行程序时 1s的运行次数大概是10的8次方,当我们上亿次的次方,在采用循环的方式就会超时,快速幂就是基于解决这种问题的方法。我们采用一个例子,让我们更加通俗易懂。 这类问题通常伴随着取模。

快速幂样例解释

	首先呢我们运算210次方
 我们普通方法 我们让一个变量为1  1*2 = 2  2*2 = 4 。。。。512 *2  =1024
 快速幂方法  我们 2^10   <=> (2*2)^5  <=> 2*(2*2*2*2)^2 <=> 2 *((2^4)*(2^4))
 这里也是有一个变量存储我们模拟一下这个过程
 res = 1 存储结果  a= 2 底数 b=10 次幂
(1)当b2的倍数时  我们 让底数翻倍 a = 2*2 = 4  b  = b/2 = 52)当b不是2的倍数时 我们让 res乘掉一个底数 让次幂继续构成2的倍数 
 	res = res*a = 4 b = b-1 = 43)当b继续是2的倍数的时候 底数继续翻倍 a = 4*4 = 16 b = b/2 = 24)当b继续是2的倍数的时候 底数继续翻倍 a = 16*16 = 256 b= b/2 = 1;
(5)当b不是2的倍数时候 res 乘掉一个底数  res = a*res = 4*256 = 1024b0的时候终止程序你会发现你就得到结果了,虽然你会发现在次方的时候快速幂需要5次,
 普通需要十次,也不快呀,因为这里我们的次幂有点小,当我们次幂非常大的时候,
 快速幂的速度就是超级快的logn级别的,260次方的次幂,我们60次就可以算出来结果,
 普通算法可是要260次方,那可是一个超级大的数呀。

快速幂代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;

int qmi(int a, int k, int p)  // 求a^k mod p
{
    int res = 1 % p;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

int main()
{
    int a,k,p; cin>>a>>k>>p;
    cout<<qmi(a,k,p)<<"\n";
    return 0;
}

龟速乘

龟速乘用于解决的问题

龟速乘用于解决溢出问题,比如我们两个数都是10^15次方,我们相乘的话会爆long long, 龟速乘就是解决这一类问题,这类问题也伴随着取余。

龟速乘样例解释&代码实现

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

/*
比如 3^4 mod = 5   a= 3 , b = 4, c = 5,res = 0;
如果 b%2==0 b = b/2 = 2, a = (a+a)%c = 6%5 = 1;
如果 b%2==0 b = b/2 = 1, a = (a+a)%c = 6%5 = 2;
如果 b%2==1 b = b-1 = 0, a = (res+a)%c = 2%5 = 2;

原理类似于快速幂,但是有一些区别 就是 原来快速幂的乘都改成了+ 这样就可以解决掉溢出问题了


*/

typedef long long LL;
LL a,b,p;
LL gui(LL a,LL b,LL p)
{
    LL res = 0;
    while(b>0)
    {
        if(b&1) res = (res+a)%p;
        b/=2;
        a = (a+a)%p;
    }
    return res;
}

int main()
{
    cin>>a>>b>>p;
    cout<<gui(a,b,p)<<"\n";
    return 0;
}