快速幂算法C++


一、前置知识

1.二进制表示数字

注意:每个十进制数都可以由唯一的二进制数表示.

EXAPMPLE:

13 = ( 1101 ) 2 = 1 × 2 0 + 0 × 2 1 + 1 × 2 2 + 1 × 2 3 13=(1101)_2=1\times2^0+0\times2^1+1\times2^2+1\times2^3 13=(1101)2=1×20+0×21+1×22+1×23

2.位运算

a.& 运算符

&运算符可以直接对二进制进行操作,1&1=1,1&0=0,0&1=0,0&0=0,因为奇数的二进制表示末尾数字都是1,所以 &可以直接用来判断奇偶性

#include <bits/stdc++.h>
using namespace std;

int main(){
	int a;cin>>a;
	if(a&1) cout<<"a是奇数"<<"\n";
	else cout<<"a是偶数"<<"\n";
	return 0;
}

b.“<<”左移 和 “>>”右移 运算符

在此处你只需要记住>>n代表除 2 n 2^n 2n,<<n代表乘 2 n 2^n 2n

EXAMPLE:

12 = ( 1100 ) 2 > > 1 − − − ( 110 ) 2 = 6 12=(1100)_2 >>1 ---(110)_2=6 12=(1100)2>>1(110)2=6

12 = ( 1100 ) 2 < < 1 − − − ( 11000 ) 2 = 24 12=(1100)_2 <<1 ---(11000)_2=24 12=(1100)2<<1(11000)2=24

3.分治思想

 分治策略(Divide and Conquer)是一种算法设计策略,通过将一个问题分解成多个相同或类似的子问题,然后递归地解决这些子问题,并将它们的解合并起来得到原问题的解。分治策略通常包括三个步骤:分解(Divide)、解决(Conquer)、合并(Combine)。

  • 分解(Divide):将原始问题划分为若干个规模较小、结构与原问题相似的子问题。这通常是通过递归地将问题划分成更小的子问题来完成的。
  • 解决(Conquer):递归地解决各个子问题。当子问题的规模足够小时(可以直接求解),不再需要继续递归时,就称为“基本情况”。
  • 合并(Combine):将子问题的解合并成原始问题的解。这一步通常在递归的过程中完成,而不是在最后进行。

分治策略的优势在于它可以将复杂的问题分解成相对简单的子问题,使得问题的求解更加清晰和高效。然而,分治策略并不适用于所有类型的问题,有时候子问题之间的合并成本可能很高,从而抵消了分解所带来的收益。

二、快速幂是什么?

在这里插入图片描述

简而言之,快速幂算法是用来快速计算指数表达式的值的一种算法,例如 2 1000000000 2^{1000000000} 21000000000,普通的计算方法 2 × 2 × 2 × . . . . . . 2\times2\times2\times...... 2×2×2×......乘1000000000-1次,而计算机1s最多运行 5 × 1 0 8 5 \times10^8 5×108次,所以普通算法无法满足要求。而快速幂算法的时间复杂度为O(log n),其中n为指数的位数,所以只需要运算28.897353次,满足要求。相比于传统的逐次相乘的方法,时间复杂度更低,尤其是在指数很大的情况下,优化效果更加明显。
 例: 2 13 2^{13} 213只需要计算3次即可得出结果,首先 13 / 2 = 6 13/2=6 13/2=6, 6 / 2 = 3 6/2=3 6/2=3, 3 / 2 = 1 3/2=1 3/2=1

注意此处对时间复杂度的优化只考虑乘法的循环次数,右移操作和内部乘法操作都视为常数操作,忽略不计,原本优化之前乘法运算要循环n次,而优化之后只需要运算log n次,如1e12最后只需要40次,所以优化效果明显。

三、算法理解+代码实现

前置知识 ( a × b × c × d ) m o d    p = ( ( ( a × b ) p × c ) m o d    p × d ) m o d    p (a \times b \times c \times d ) \mod p = (((a \times b) p \times c) \mod p \times d) \mod p (a×b×c×d)modp=(((a×b)p×c)modp×d)modp

1.经典理解方法

3 10 = ( 3 2 ) 5 = 9 5 = 9 × 9 4 = 9 × ( 81 ) 2 = 9 × ( 81 2 ) 1 3^{10}=(3^2)^5=9^5=9\times9^4=9\times(81)^2=9\times({81}^2)^1 310=(32)5=95=9×94=9×(81)2=9×(812)1

//此处以3^10为例进行解释说明
#include <bits/stdc++.h>
using namespace std;

#define int long long
const int mod=998244353;

int quickrow(int a,int b){//注意a表示底数,b表示指数
    int ans=1;//用来储存答案
    while(b){//若指数不为零,就进行运算
        if(b%2==1){//若指数为奇数,则提出一个底数,进行偶指数运算,如9^5变成9*9^4
            ans=ans*a%mod;//将拿出来的底数乘到ans中
            a=a*a%mod;//底数平方
            b/=2;//指数除2
        }
        else {//偶数直接进行指数和底数操作
            a=a*a%mod;
            b/=2;
        }
    }
    return ans%mod;//返回答案
}
signed main(){
	int a,b;cin>>a>>b;
	cout<<quickrow(a,b);
	return 0;
}

2.二进制分解理解法(精简版)

2 13 = 2 ( 1101 ) = 2 8 × 2 4 × 2 1 2^{13}=2^{(1101)}=2^8\times2^4\times2^1 213=2(1101)=28×24×21

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int mod=998244353;

int quickrow(int a,int b){
    int ans=1;
    while(b){//将指数看成二进制形式
        if(b&1) ans=ans*a%mod;//如果是1说明存在
        a=a*a%mod;//a不管二进制位是0还是1,都不断的自乘
        b>>=1;//右移一位
    }
    return ans%mod;
}
signed main(){
	int a,b;cin>>a>>b;
	cout<<quickrow(a,b);
	return 0;
}

总结

此算法较为常用,建议记住,下一篇讲解利用快速幂求解逆元
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iceooly

~来一份支持吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值