首先我们要知道什么是快速幂
快速幂就是快速算底数的n次幂。其时间复杂度为 O(logN)
显然就是一个数的n次方,具体来看一道题:
给你两个数A和B,计算A的B次方,输出A的B次方的最后三位数所表示的整数。
这个是我在大一暑假培训时的一道题,也是杭电oj上的链接地址:hdu-2035
这道题大眼一看,很简单,使用一个循环就可以算出来了,
但如果计算一个很大的数,例如2的10000次方,计算机没有那么大的空间,就会出现溢出,所出的模值自然是不准确的,所以是不可取的。
那么我们就要用位运算的方法,具体的方法如下:
举一个例子来说,拿a的23次方为例,如果采用一个简单的循环,那么我们需要循环23次,复杂度显然为O(n),但我们知道23存储在计算机中是10111
即23=2的4次方+2的2次方+2的1次方+2的0次方=t;
所以a的23次方=a的t次方,这样以来大大减少了时间复杂度,而且我们可以通过求各个子项的模值来得到结果。如下第二个式子:
( a + b ) % c = ( ( a % c ) + ( b % c ) ) % c
( a * b ) % c = ( ( a % c ) * ( b % c ) ) % c
( a – b ) % c = ( ( a % c ) – ( b % c ) ) % c
再继续看a的23次方,10111
有了上面的想法 我们可以使用位运算,通过的23(下述为n)的二进制权位依次从最低位算。
从最低位开始看,定义一个ans用来输出结果,首先ans=1;我们要得到最后一位,显然用n&1,即可得到最低位是1,显然要用ans* a;此时ans=a;接下来我们需要ans乘以a^2才对,这时我们需要让a=a的平方才行,所以a*=a;但如果要想实现ans乘以此时的a;需要用到上面的思想,我们仍希望让二进制的最后一位仍是1;那么我们可以用n>>1;这样此刻的倒数第二位就变成了倒数第一位,以23为例,此时就变成了1011;再用n&1,判断出仍为1,就可以向上述一样ans=ansa,此刻ans=a的三次方,a=a的平方,我们知道接下来想要ans去乘以的a的四次方,所以此刻再用一次a=a,a就等于了a的四次方;继续n&1;得到101,然后继续判断最低位,仍然是1,所以ans=ansa;此时ans等于a的七次方,这时我们希望让ans乘以a的八次方;而a仍需要累乘。即a=a;此时a等于a的八次方,n>>1;此时n=10;继续判断最后一位为0;此时我们不希望ans去乘以a,因为还有2位,如果此时去乘,还要多进行一次操作,所以如果判断出0;即不去执行ans乘以a的操作才是我们想要的操作,而a需要继续累乘,即a此时等于a的16次方,n>>1,此时n=1;即ans*=a;这时ans就是我们想要的值了。
如下是我的代码实现
#include
using namespace std;
int pow(int a,int n)
{
int ans=1;
while(n>0)
{
if(n & 1==1)
{
ans*=a;
}
a*=a;
n=n>>1;
}
return ans;
}
int main()
{
int a;
int n;
cin>>a>>n;
cout<<pow(a,n)<<endl;
return 0;
}