逆元用于求 $ \frac{a}{b} (mod\ p)$ 的结果
第一种方法:拓展欧几里得
- 利用拓欧求解同余方程:\(a*x ≡ c\ (mod\ b)\) 的 \(c = 1\) 的情况
- 就可以转化成求解 \(a*x+b*y=1\) 这个方程
void exgcd(ll a,ll b,ll &x,ll &y) //解 ax + by = gcd(a,b) 的一组整数解
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,x,y);
ll s_x=x;
ll s_y=y;
x=s_y;
y=s_x-(a/b)*s_y; //时间复杂度近似为logn
}
//拓展欧几里得求逆元
ll inv1(ll a)
{
ll x,y;
exgcd(a,mod,x,y);
return (x%mod+mod)%mod;
}
第二种方法:快速幂
- 这个做法要利用费马小定理
若\(p\)为素数, \(a\)为正整数,且\(a,p\)互质,则有\(a^{p - 1}≡1(mod\ p)\)。
- 带入即可得到:$$x≡a^{p - 2}(mod\ p)$$
ll fastpow(ll a,ll b) //快速幂(最多算到2^62)
{
ll res=1;
while(b){
if(b&1) res=(res*a)%mod; //取模运算
a*=a;
b>>=1;
}
return res;
}
//2.费马小定理求逆元
ll inv2(ll a)
{
return fastpow(a,mod-2);
}
第三种方法:线性算法
- 用于求一连串数字对于一个 \(mod\ p\) 的逆元。
inv[1] = 1;
for(int i = 2; i < p; i ++)
inv[i] = (p - p / i) * inv[p % i] % p;
一个用于第三种方法的例题:
P3811 【模板】模意义下的乘法逆元
点击查看代码
#include<cstdio>
#define ll long long
using namespace std;
const int maxn = 3e6 + 5;
ll inv[maxn];
int main(){
inv[0] = 0, inv[1] = 1;
int n, p;
scanf("%d %d", &n, &p);
printf("1\n");
for(int i = 2; i <= n; i ++)
inv[i] = ((ll)p - (p / i)) * inv[p % i] % p, printf("%lld\n", inv[i]);
return 0;
}