逆元的三种计算方法

逆元的三种计算方法

  • 快速幂求逆元
  • 扩展欧几里得求逆元
  • 线性求逆元

快速幂求逆元

前提:p为质数

由费马小定理知:在p为质数的情况下,\(a^{p-1}(mod\quad p)\)的变形为:\(a\times a^{p-2}(mod\quad p)\)

\(a^{p-2}(mod\quad p)\)就是逆元

int inv(int x,int p) {return qmi(x, p - 2, p) % p;}

int res = inv(a, p);
if (a % p) printf("%d\n", res);
else puts("impossible");

扩展欧几里得求逆元

前提:a与p互质

\(ax \equiv 1\ (mod\ p)\)

  1. 将乘法逆元转化为不定方程,等价变形\(ax+py = 1\)
  2. 扩展欧几里得求\(ax + py = gcd(a,p)\)的解\(x\)\((x\%p+p)\%p\)即答案
int a, p, x, y;
cin >> a >> p;
exgcd(a, p, x, y);
cout << (x % p + p) % p << endl;

线性求逆元

线性求逆元

在求某个数的逆元时使用费马小定理或扩展欧几里得定理,而在求\(1\)\(p - 1\)连续的关于\(p\)的逆元,而\(p\)较大时,时间复杂度吃不消,可以使用下面算法在\(O(n)\)的时间复杂度内解决

前提:\(p\)为素数

递推式:

\[inv[i] = (M - M\ /\ i)\ *\ inv[M\ \%\ i]\ \%\ M \]

推导过程:

\[\text{设:}t = M/i\quad k = M\%i \\ \Rightarrow t*i + k \equiv 0 (mod\ i) \\ \Rightarrow -t * i \equiv k(mod\ M) \\ \text{将上面两式同时除以i * k得:}\ -t * inv[k] \equiv inv[i](mod\ M) \\ \text{替换t和k得:}\ inv[i] = (M - M / i) * inv[M \% i]\% M \\ \]

\(1\)的逆元为\(1\),初始化\(inv[0] = inv[1] = 1\),这样就可以通过递推式得到\(1\to p\ (mod\ p)\)的所有逆元了

inv[0] = inv[1] = 1;
for (int i = 2; i <= n; i++) {
	inv[i] = (p - p / i) * inv[p % i] % p;
}
posted @ 2023-09-14 21:35  -37-  阅读(231)  评论(0编辑  收藏  举报