当前位置:首页 > 算法 > 正文内容

【分治】----快速幂

亿万年的星光4年前 (2021-01-28)算法22865
1.幂

幂(power)是指乘方运算的结果。n^m指该式意义为m个n相乘。把n^m看作乘方的结果,叫做n的m次幂,也叫n的m次方。

2.幂的数学表示和规则

23 * 24 =27


34 * 34=38


3.分治法求快速幂

在平常中我们如果遇到求 ab的时候,可能是一个一个挨个乘起来,也就是将a乘b次,如果b的值非常大时,在算法竞赛中又有时间限制,累次乘几乎是不行的。(不要说这个时候用pow() 函数)例如:21000,用循环累次乘的话需要1000次。

现在我们如果要求211的值,那么就要计算 22222222222

根据前面幂的运算法则,可以得出211=25 * 25 * 21    。  25=22 * 22 *21 。 22=21 * 21

再例如:现在我们如果要求 216的值,那么就要计算 16个2相乘。根据前面幂的运算法则,可以得出

216=28 * 28  。 28=24 * 24  。 24=22 * 22  。  22=21 * 21

从上面两个例子可以看出,如果用类似于次方一半的方式进行累乘,那么需要计算的次数可以减少很多。这就是分治法求快速幂的核心。

再来找一下分治法求快速幂的规律。可以看出上面两个的主要区别在于次方是奇数还是偶数,如果是次方b是偶数,只需要每次乘ab/2
 ,然后将次方b缩减一半即可。如果次方b是个奇数,可以先将这个a自乘一次,这样剩余的b-1次方就是偶数了。

快速幂是一个将底数等价增大,指数等价缩小的过程。总结:b是偶数:image.png b是奇数:

image.png  我们用res表示结果;那么求ab的过程代码描述如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
    int a,b,res=1; //定义底数,次数,结果
    cin>>a>>b;
    while(b!=0) //次方减半不到0时继续
    {
        if(b%2==1)  //如果b是奇数,(最后一次一定是奇数)
            res=res*a;  //  先乘自己一次,这样就能一半是偶数
        a=a*a;  // a^2 ,a^4, a^8 ...
        b=b/2; // 这个地方如果是b>>=1 速度更快 ,缩减一半工作量
    }  
    cout<<res<<endl;
    return 0;
}

image.png



image.png


311的动图演示。


4.递归法求快速幂

#include<cstdio>
int pow_mod(int a ,int n) {
   if(n == 0)
       return 1;
   int x = pow_mod(a,n / 2);
   long long ans = (long long)x * x ;
   if(n%2 == 1)
       ans = ans *a ;
   return (int)ans;
}
int main() {
   int a,b;
   scanf("%d%d",&a,&b);
   printf("%d",pow_mod(a,b));
   return 0;
}

5.迭代法求快速幂
#include<bits/stdc++.h>
using namespace std;
long long pow_d(long  a,long  b){
   long ans=1;
   while(b>0){
       if(b&1){//如果b的二进制末尾为1 ,就相当于被选中了。
      //就如2^13 ==> 2^(13==>1101)==> 2^(1101) ==> 3 2 0 号为 1 那么被选中 ==> 2^13 = 2^8 *  2^4 * 2^1
           ans=ans*a;//令ans累积上a
       }
       a=a*a;//令a平方
       b>>=1;//将b的二进制右移一位即
   }
   return ans;
}
int main(){
   long long  a,b;
   cin>>a>>b;
   long long  result=pow_d(a,b);
   cout<<result<<endl;
   return 0;
}

6.快速幂中中的取余运算

搜索快速幂的时候经常发现最后有个取余运算,主要原因是因为现在oj网站的题或者竞赛的题,如果a的b次幂且b很大,那么题中大多会让你把结果对一个数取余也就是求模,例如a^b%c这种。

介绍一个公式:
(a*b)%m = (a%m * b%m) %m

所以在一些求快速幂中会出现取余现象。

例题

【题目描述】

假设今天是星期日,那么过 a^b天之后是星期几?
【输入描述】

两个正整数 a,b,中间用单个空格隔开。100000<a≤100,0<b≤10000。
【输出描述】

一个字符串,代表过 a^b 天之后是星期几。
其中,Monday 是星期一,Tuesday 是星期二,Wednesday 是星期三,Thursday 是星期四,Friday 是星期五,Saturday 是星期六,Sunday 是星期日。
【样例输入】

3 2000
【样例输出】

Tuesday

【分析】上面这道题目出现了2000次方,比较大所以考虑到取余的问题,实际上我们只有按照题目要求,每次运算求幂的时候对7取余即可。类似下面这样:

#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
    int a,b,res=1,m=7; //定义底数,次数,结果,取余
    cin>>a>>b;
    while(b!=0) 
    {
        if(b%2==1)  //如果b是奇数,(最后一次一定是奇数)
            res=res*a%m;  
        a=a*a%m;   
        b=b/2; 
    }   
    cout<<res<<endl;
    return 0; 
}

扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【二分】----基础用法

【二分】----基础用法

0.二分法简介二分法是一种查找算法要求:数据必须是有序序列核心思想:掐头去尾取中间1. 引入对于一个有序数组,如{1,3,6,8,23,56,78,99},如果我们要查找其中的一个数78的下标位置,按...

【算法】高精度(2)

五、高精度处理进位与借位    其实也很简单,我们再来模拟一下,1439+887的时候,首先我们最低位相加,得到16,那么答案最低位就是6,再进个1,然后两数的十位相加,...

【贪心】----找零钱问题

一、找零钱问题例题1:有 1 元,5元,10元,20元,100元,200元的钞票无穷多张。现在使用这些钞票支付X元,最少需要多少张钞票。X = 628最佳支付方法:3张200块的,1张20块的,1张5...

【贪心】最大子矩阵

【题目描述】已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1X1)子矩阵。比如,如下4 x 4的矩阵0    -2&...

【贪心】区间调度

【贪心】区间调度

【题目描述】有n项工作,每项工作分别在si时间开始,在ti时间结束。对于每项工作,你都可以选择参与与否。如果选择了参与,那么自始至终都必须全程参与。此外,参与工作的时间段不能重叠(即使是开始与结束的瞬...

【排序】----插入排序

【排序】----插入排序

1.基本思想在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。2.过程·(1)从第一个元素开始,该元素可以...