乘法逆元问题,常常以这这样的形式出现
a/b ( mod p )=a*(p1)( mod p),b是关于p的逆元。
求解乘法逆元的几种方法:
1 费马小定理,a在模p下的逆元,要求p为质数。
ll fpm(ll x, ll power, ll mod) {
x %= mod;
ll ans = 1;
for (; power; power >>= 1, (x *= x) %= mod)
if(power & 1) (ans *= x) %= mod;
return ans;
}
int main() {
ll x = fpm(a, p - 2, p); //x为a在mod p意义下的逆元
}
2 拓展欧几里得。
exgcd,求a在模p下的逆元,要求a和p互质,但是p不一定是质数。
code:
void Exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) x = 1, y = 0;
else Exgcd(b, a % b, y, x), y -= a / b * x;
}
int main() {
ll x, y;
Exgcd (a, p, x, y);
x = (x % p + p) % p;
printf ("%d\n", x); //x是a在mod p下的逆元
}
3 线性乘法
常用于求一连串数字对于一个 mod p 的逆元。要求p为质数
code:
inv[1] = 1;
for(int i = 2; i <=n; ++ i)
inv[i] = (p - p / i) * inv[p % i] % p;
证明: p=k*i+r,对p取模可得,k*i+r=0(mod p),两端同时乘以i的逆元[i]和r的逆元[r]可得,k*[r]+[i]=0(mod p),
[i]=-k*[r]=-k*[p%i],k=p/i,所以[i]=(-p/i)*([p%i]),[i]=(p-p/i)*[p%i]%p;
4 递推法求阶乘逆元:
code:
void init() {
fact[0] = 1;
for (int i = 1; i < maxn; i++) {
fact[i] = fact[i - 1] * i %mod;
}
inv[maxn - 1] = power(fact[maxn - 1], mod - 2);
for (int i = maxn - 2; i >= 0; i--) {
inv[i] = inv[i + 1] * (i + 1) %mod;
}
}
证明过程:设n!的逆元为[n],我们求一下(n-1)!的逆元。
n!*[n]=1(mod p) 将n!拆开, (n-1)!*n*[n]=1(mod p)所以,(n-1)!的逆元就是n[n]。
所以递推式inv[n]=inv[n+1]*(n+1)%p;
https://blog.csdn.net/qq_35416331/article/details/81059747