快速幂算法主要应用于求幂模的问题。
我们可以先定义一个问题:
如何求2^31的最后一位数?显而易见,结果当然是8.这个问题是具有特殊性的,可以用某些特殊解法来处理。但是作为我们对快速幂的学习例程来看,我们需要从特殊问题中寻找一般算法。
对于这个问题,最脑残的算法是:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int i,j,m=1,n,t;
cin>>t>>n;
while(--n>=0)m*=t;
cout<<m%10<<endl;
return 0;
}
显见,这个算法对于大数据并不适用,可能造成内存溢出,因此我们做出:
while(--n>=0)m=(m*t)%10;
应用了离散数学中的一个定理:积的模等于模的积的模。
但是,时间复杂度并没有任何的改观。
为了解决时间复杂度问题,我们可以思考:对于n个a的积问题,是否可以转化为2*(n/2)个a的积的问题?答案是肯定的。再这样细分下去,不难想到,我们可以采用二分思想来解决这个问题。只是这里,我们并不把二分单独形成一个函数,我们仅仅采用while循环来解决二分算法的实现。(也称:二分幂)
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
long long i,j,m=1,n,t,base;
cin>>t>>n;
t%=10;
while(n)
{
if(n%2==1)
m*=t;
t=(t*t)%10;
n/=2;
}
cout<<m%10<<endl;
return 0;
}
经检验,这种算法可以在数据量为指数为10^16甚至更大时瞬间得出结果。
事实上,这也就是最基本的快速幂算法。
另则,在以上例程中我们使用的都是10作为基本模。可以单独导出一个变量Md来作为模数。这样可以实现任意模的快速幂。
对于更为复杂的问题,可能会用到快速幂与高精度的结合,以及快速幂的位运算实现方法,本文在此不作深入研究。