快速幂(Fast power)
简介(Introduction)
快速幂是快速计算底数的 $n $ 次幂
对于 $a^b \quad mod \quad p $ ,当 $a $ 或者 $b $ 非常大时我们无法直接算出来结果
描述(Description)
- ,就需要进行拆分。
- 而快速幂算法可以高效地做到这一点,快速幂算法的核心思想是每一步都把指数分成两半,而相应的底数做平方运算。
- 这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。
- 时间复杂度为: $O(logn) $
代码(Code)
// C++ Version
* 3 ^ 11 = ?
* 11 = 1011
* 3 ^ 1 = 3 ------ 3 ^ 1 = 3
* 3 ^ 2 = 9 ------ 3 ^ 2 = 9
* 此位二进制为0 ------ 9 ^ 2 = 81
* 3 ^ 8 = 6561 ------ 81 ^ 2 = 6561
*
* 3 ^ 15 = 3 × 9 × 6561 = 177147
*/
int power(int a, int b, int p) {
int ans = 1 % p;
for ( ; b; b >>= 1) {
if (b & 1) ans = (ll) ans * a % p;
a = (ll) a * a % p;
}
return ans;
}
应用(Application)
快速幂求逆元
给定 $n $ 组 $a_i, p_i $ 其中 $p_i $ 是质数,求 $a_i $ 模 $p_i $ 的乘法逆元,若逆元不存在则输出 $impossible $。
注意:请返回在 $0 ∼ p − 1 $之间的逆元。输入格式
第一行包含整数 $n $。
接下来 $n $ 行,每行包含一个数组 $a_i, p_i $ 数据保证 $p_i $ 是质数。输出格式
输出共 $n $行,每组数据输出一个结果,每个结果占一行。
若 $a_i $模 $p_i $ 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 $impossible $。数据范围
$1 ≤ n ≤ 10^5 $
$1 ≤ a_i, p_i≤ 2 × 10 $9输入样例:
$3 $
$4 3 $
$8 5 $
$6 3 $输出样例:
$1 $
$2 \( \)impossible $
乘法逆元的定义:
若整数 $b, m $互质,并且对于任意的整数 $a $,如果满足 $b\ |\ a $,则存在一个整数 $x $,使得 $a\ /\ b\ ≡\ a\ * x \ mod\ m $,
则称 $x $ 为 $b $ 的模 $m $ 乘法逆元,记为 $b^{−1}\ mod\ \ m $。
$b $ 存在乘法逆元的充要条件是 $b $ 与模数 $m $ 互质。当模数 $m $ 为质数时, $b^{m−2} $ 即为 $b $ 的乘法逆元
-
分析:
-
需要寻找一个 $x $,使得 $a\ /\ b\ ≡\ a\ *\ x\ mod\ m $。
-
而我们最后定义 $x = b^{−1} $ (这里只是表示逆元,而不是负一次方)
-
证明
$(a\ /\ b)\ %\ p\ =\ m\ ······\ (1) \( \)ax\ %\ p\ =\ m\ ······\ (2) $
首先把 $(1) $ 式两边同时乘 $b $得到: $a\ %\ p\ =\ mb\ %\ p\ =\ (m\ (b\ %\ p)\ )\ %\ p $。
如果 $a, b < p $,我们可以把上式化简为 $a = mb\ %\ p $。
上式两边同乘 $x $ 并且联立 $(2) $ 式可以得到: $ax\ %\ p\ =\ m %\ p\ =\ xbm\ %\ p $,
由此可得 $bx % p ≡ 1 $
-
由于本题保证 $p $ 是质数和式子的特殊性可以使用费马定理
费马定理:
如果我们定义一个 $p $为素数,且定义 $b $, $b % p ≠ 0 $,则 $b $p-1 $ ≡ 1(mod p) $
即:如果 $b $和 $p $互质,则 $b $ 的 $p-1 $ 次方模 $p $ 等于 $1 $
-
-
题解:
// C++ Version #include<iostream> using namespace std; typedef long long LL; int binpow(int a, int k, int p){ int res = 1; while(k){ if(k & 1) res = (LL) res * a % p; k >>= 1; a = (LL) a * a % p; } return res; } int main(){ ios::sync_with_stdio(false); cout.tie(0); cin.tie(0); int n; cin >> n; while(n--){ int a, b; cin >> a >> b; if(a % b == 0) cout << "impossible" << endl; else cout << binpow(a, b - 2, b) << endl; } return 0; }