快速幂是在 O(log k) 的复杂度下计算 ak 的结果,一般为了防止数太大结果需要对 p 取模。
快速幂的思想就是反复对底数求平方、指数整除2,由于 ak=(a2)2k,只要分奇偶判断一下 k 的值就可以了。
1 2 3 4 5 6 7 8 9 10 11
typedeflonglong 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; }
或者可以用二进制的方式理解,将 k 拆成 ∑i=0Nbi⋅2i(bi∈{0,1}) 的形式,然后放到指数上,由指数的运算性质可以知道 ak=a20⋅b0⋅a21⋅b1⋯a2n⋅bn,所以这一串的底数是 a1,a2,a4,a8,⋯,a2n,于是可以写成下面的形式:
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 乘法逆元,记为 b−1(mod m)。b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时,bm−2 即为 b 的乘法逆元。
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; }
intmain(){ 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'; } }