快速幂算法
问题引入
给出三个整数 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} [Fn−1Fn−2] [ 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} [FnFn−1]
已知: 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]n−2 =
[
F
n
F
n
−
1
]
\begin{bmatrix} &F_{n}& & F_{n-1} \end{bmatrix}
[FnFn−1]
利用矩阵快速幂可以在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;
}