本文已参与「新人创作礼」活动,一起开启掘金创作之路
快速幂
快速幂用于解决的问题
在我们的学习语法的时候,比如我们求一个2的十次方的数字,我们可以采用循环一下就是枚举一下循环从1~10,这样我们就可以求出我们想要的答案,当次方为一千,一万,十万,我们这个方法都可以做,但是当我们乘上一个上亿级的次方,我们这样的方法就行不通了,我们知道c++在运行程序时 1s的运行次数大概是10的8次方,当我们上亿次的次方,在采用循环的方式就会超时,快速幂就是基于解决这种问题的方法。我们采用一个例子,让我们更加通俗易懂。 这类问题通常伴随着取模。
快速幂样例解释
首先呢我们运算2的10次方
我们普通方法 我们让一个变量为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)当b是2的倍数时 我们 让底数翻倍 a = 2*2 = 4 b = b/2 = 5
(2)当b不是2的倍数时 我们让 res乘掉一个底数 让次幂继续构成2的倍数
res = res*a = 4 b = b-1 = 4
(3)当b继续是2的倍数的时候 底数继续翻倍 a = 4*4 = 16 b = b/2 = 2
(4)当b继续是2的倍数的时候 底数继续翻倍 a = 16*16 = 256 b= b/2 = 1;
(5)当b不是2的倍数时候 res 乘掉一个底数 res = a*res = 4*256 = 1024
当b为0的时候终止程序你会发现你就得到结果了,虽然你会发现在次方的时候快速幂需要5次,
普通需要十次,也不快呀,因为这里我们的次幂有点小,当我们次幂非常大的时候,
快速幂的速度就是超级快的logn级别的,2的60次方的次幂,我们60次就可以算出来结果,
普通算法可是要2的60次方,那可是一个超级大的数呀。
快速幂代码实现
#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;
}