让幂运算更效率——快速幂

  在日常解决问题的过程中,我们常常会遇到求ab类似的问题,对于这种问题,我们一般的解决方法就是最朴素的方法就能解决,它的时间复杂度为O(b)。
1 int power(int a,int b)    //求a的b次方
2 {
3     int i,ans=1;
4     for(i=0;i<b;i++)
5         ans*=a;
6     return ans;
7 }

但是对于某些题目,当b的数据变大的时候,可能就会超时,这时候我们就需要用快速幂来优化我们的程序了。

 

一、快速幂
快速幂的原理来自于十进制二进制相互转换的加权系数法,对于任意一个十进制数,我们可以把它写成2k1+2k2+2k3+…+2kn+…(k=0,1,2…),继而转化为二进制,如10=21+23=(1010)2。那么对于ab的次数b来说,也是如此。我们可以把b拆成2k1+2k2+2k3+…+2kn+…(k=0,1,2…),那么ab就变成了a(2^k1+2^k2+2^k3+…+2^kn+…)(k=0,1,2…),继而可以化成a2^k1×a2^k2×a2^k3×…×a2^k1。这样一来,我们就把原来的时间复杂度O(b)压缩到O(log2b),这是一个很可观的改进。
怎么用代码来实现呢?这里我们需要用到两个位运算&和>>,其中&是按位与,我们在代码中用(n&1)来判断n的二进制最后一位是不是1。n>>1的作用是二进制数左移一位,效果等同于除以2,但是时间要比除以2稍快。
综上,我们就可以得到快速幂的实现代码了。
 1 long long fastpow(long long n,long long multi)
 2 {
 3     long long ans=1,base=n;
 4     while(multi)
 5     {
 6         if(multi&1) ans=(ans*base);
 7         base=(base*base);
 8         multi>>=1;
 9     }
10     return ans;
11 }

但是在实际解题中很多情况下进行不了几次幂运算就会溢出,所以常常会让我们取模,下面我们来解决这个问题。

 

二、快速幂取模
求解快速幂取模的问题并不需要对算法做太多的改动,在乘运算时加上取模即可,但要注意取模尽量要考虑全面,因为不一定什么地方就会爆掉了。
代码如下:
 1 long long fastpow(long long n,long long multi,long long mod)
 2 {
 3     long long ans=1,base=n;
 4     while(multi)
 5     {
 6         if(multi&1) ans=(ans*base)%mod;
 7         base=(base*base)%mod;
 8         multi>>=1;
 9     }
10     return ans%mod;
11 }

 

三、矩阵快速幂

(施工中orz)

 

四、相关题目
1.快速幂例题  Luogu P1226
代码:
 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 long long mod,n,multi;
 6 
 7 long long fastmulti(long long n,long long multi,long long mod)
 8 {
 9     long long ans=1,base=n;
10     while(multi)
11     {
12         if(multi&1) ans=(ans*base)%mod;
13         base=(base*base)%mod;
14         multi>>=1;
15     }
16     return ans%mod;
17 }
18 
19 int main()
20 {
21     scanf("%lld%lld%lld",&n,&multi,&mod);
22     long long ans;
23     ans=fastmulti(n,multi,mod);
24     printf("%lld^%lld mod %lld=%lld",n,multi,mod,ans);
25     return 0;
26 }
Luogu P1226

 

Author : Houge  Date : 2019.6.2

Update log : 

posted @ 2019-06-04 10:16  CSGO_BEST_GAME_EVER  阅读(453)  评论(0编辑  收藏  举报