简介

快速幂是在 O(log k) 的复杂度下计算 aka^k 的结果,一般为了防止数太大结果需要对 pp 取模。

快速幂的思想就是反复对底数求平方、指数整除2,由于 ak=(a2)k2a^k=(a^2)^{\frac{k}{2}},只要分奇偶判断一下 kk 的值就可以了。

1
2
3
4
5
6
7
8
9
10
11
typedef long long ll;

ll fastpow(ll a, ll k, ll p) {
ll ans = 1;
while (k) {
if (k % 2 == 1) ans = (ans * a) % p;
a = (a*a) % p;
k /= 2;
}
return ans;
}

或者可以用二进制的方式理解,将 kk 拆成 i=0Nbi2i(bi{0,1})\sum_{i=0}^N b_i\cdot2^i(b_i\in\{0, 1\}) 的形式,然后放到指数上,由指数的运算性质可以知道 ak=a20b0a21b1a2nbna^k=a^{2^0\cdot b_0}\cdot a^{2^1\cdot b_1}\cdots a^{2^n\cdot{b_n}},所以这一串的底数是 a1,a2,a4,a8,,a2na^1, a^2, a^4, a^8, \cdots, a^{2^n},于是可以写成下面的形式:

1
2
3
4
5
6
7
8
9
ll fastpow(ll a, ll b, ll p) {
ll ans = 1;
while (b) {
if (k & 1) ans = (ans * a) % p;
a = (a*a) % p;
k >>= 1;
}
return ans;
}

快速幂求逆元

给定 n 组 a, p, 其中 p 是质数,求 a%p 的乘法逆元,若逆元不存在则输出 impossible
注意:请返回在 0∼p−1 之间的逆元。

注释:若整数 b,m 互质,并且对于任意的整数 a,如果满足 a 是 b 的倍数,则存在一个整数 x,使得 a/b=a*x % m,则称 x 为 b 的模 m 乘法逆元,记为 b1(mod m)b^{-1}(\text{mod }m)。b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时,bm2b^{m-2} 即为 b 的乘法逆元。

其实就是求 a^(p-2)%p,判断一下 a 是不是 p 的倍数就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
typedef long long ll;

ll fastpow(ll a, ll k, ll p) {
ll ans = 1;
while (k) {
if (k & 1) ans = (ans * a) % p;
a = (a * a) % p;
k >>= 1;
}
return ans;
}

int main() {
cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
int n;
cin >> n;
while (n--) {
int a, p;
cin >> a >> p;
if (a % p == 0) cout << "impossible\n";
else cout << fastpow(a, p-2, p) << '\n';
}
}