快速幂算法

快速幂算法

问题引入

给出三个整数 a,b,m,求 a b a^b ab mod m 的值。
对于全部数据,1≤ a,b,m ≤ 1 0 9 10^9 109

定义

快速幂是一个在O(logn)时间内求 a b a^b ab的算法,暴力计算需要O(n)。

过程

对于 a b a^b ab,我们对b进行二进制拆分。如 a 19 a^{19} a19, 19 = 16 + 2 + 1 = ( 10011 ) 2 {(10011)}_2 (10011)2。那么 a 19 a^{19} a19 = a 16 a^{16} a16 * a 2 a^{2} a2 * a 1 a^{1} a1。对于任意的正整数N,我们可以都使用log(N) + 1位2进制表示,所以我们可以在log(N)的时间内求出 a N a^{N} aN
下面给出递推代码:

int qpow(int a, int b){
    int res = 1;
    while(b){
        if(b & 1) res = 1ll*res*a%m;
        a = 1ll*a*a%m;
        b >>=1;
    }
    return res;
}

应用

模意义下取幂

这是一个非常常见的应用,例如它可以用于计算模意义下的乘法逆元。

既然我们知道取模的运算不会干涉乘法运算,因此我们只需要在计算的过程中取模即可。

int qpow(int a, int b, int mod){
	int res = 0;
	while(b){
		if(b & 1) res = 1ll* res * a % mod;
		a = 1ll* a * a % mod;
		b >>= 1;		
	}
	return res;
}

矩阵快速幂加速递推

问题引入 :计算斐波那契数列第N项 F N F_N FN, N <= 2e9。

根据斐波那契数列 递推公式的矩阵形式:

[ F n − 1 F n − 2 ] \begin{bmatrix} &F_{n-1}& & F_{n-2} \end{bmatrix} [Fn1Fn2] [ 1 1 1 0 ] \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} [1110] = [ F n F n − 1 ] \begin{bmatrix} &F_{n}& & F_{n-1} \end{bmatrix} [FnFn1]

已知: F 1 F_1 F1 = F 2 F_2 F2 = 1,根据递推公式

[ 1 1 ] \begin{bmatrix} &1& & 1 \end{bmatrix} [11] [ 1 1 1 0 ] n − 2 \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n - 2} [1110]n2 = [ F n F n − 1 ] \begin{bmatrix} &F_{n}& & F_{n-1} \end{bmatrix} [FnFn1]
利用矩阵快速幂可以在O(logn)内求出斐波那契数列第N项

struct Matrix{
    int a[3][3];
    Matrix() { memset(a, 0, sizeof(a)) ;}
    Matrix operator* (const Matrix &b) const{
        Matrix res;
        for(int i = 1; i <= 2; i++){
            for(int j = 1; j <= 2; j++){
                for(int k = 1; k <= 2; k++){
                    res.a[i][j] = (res.a[i][j] + 1ll*a[i][k] * b.a[k][j] % mod ) % mod;
                }
            }
        }
        return res;
    }
}base, ans;
void init(){
    base.a[1][1] = base.a[1][2] = base.a[2][1] = 1;
    ans.a[1][1] = ans.a[1][2] = 1;
}
void qpow(int b){
    Matrix res;
    res.a[1][1] = res.a[2][2] = 1;
    while(b){
        if(b & 1) res = res * base;
        base = base * base;
        b >>= 1;
    }
    ans = ans * res;
    cout << ans.a[1][1] << endl;
}
  • 28
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值