快速幂

首先我们要知道什么是快速幂
快速幂就是快速算底数的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<iostream>
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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值