乘法逆元
乘法逆元简介
a存在模p的乘法逆元的充要条件是gcd(a,p)=1,即a与p互质。
若a,b不互素,则a必然不存在模b的逆元。
0没有逆元
费马小定理求乘法逆元[\(\mathrm{ax\equiv 1({\mathrm{mod}}\, m)}\)]
若a,m不互质,则a必然不存在模m的逆元,并且0没有乘法逆元。
如果p是一个质数,而整数a不是p的倍数,则有a(p-1)===1(modp),则a*a(p-1)===1(modp)。
注意:乘法逆元不一定是存在的。a 存在乘法逆元的充要条件是 a 与模数 p 互质。当模数 p 为质数时,a^(p−2) 即为 a 的乘法逆元。
[证明]
ll qmi(ll x,ll n,ll p){
ll res=1;
while(n){
if(n&1) res=res*x%p;
x=x*x%p;
n>>=1;
}
return res;
}
ll gcd(ll x,ll y){
return y?gcd(y,x%y):x;
}
void solve(){
ll a,p;
cin>>a>>p;
if(gcd(a,p)==1) cout<<qmi(a,p-2,p)<<endl;
else cout<<"impossible"<<endl;
}
扩展欧几里得求乘法逆元[\(\mathrm{ax\equiv 1({\mathrm{mod}}\, m)}\)]
对于 modp 比较大的时候效率更好
拓欧求解 线性同余方程axc(mod b) 的c1的情况,可以转化为解ax+b*y=1这个方程。
当a与p互质,但p不是质数的时候也可以使用。
对于三个自然数a,b,c,求解ax+by=c的(x,y)的整数解。
首先我们要判断是否存在解,对于这个存在整数解的充分条件是 gcd(a,b) | c ,也就是说 c为 a,b 最大公因数的一个倍数。
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;
}
ll a,p;
void solve(){
ll x,y;
exgcd(a,p,x,y);
x=(x%p+p)%p;
cout<<x<<endl;
}
区间[1,n]乘法逆元的线性求法
1≤n≤3×10^6,n<p<20000528。
公式:\(\mathrm{inv[i]=((p-\lfloor\frac pi\rfloor)\times inv[p\%i])\%p}\)
int inv[3000010];
int n,p;
void solve(){
cin>>n>>p;
inv[1]=1;
for(int i=2;i<=n;i++){
inv[i]=((ll)p-p/i)*inv[p%i]%p;
}
for(int i=1;i<=n;i++) cout<<inv[i]<<endl;
}
区间[1,n]阶乘逆元的线性求法
我们可以考虑用费马小定理先求出最大那个阶乘的逆元,然后再往回推。
逆元就可一看做是求倒数.
公式:\(\begin{aligned}\frac{1}{(n+1)!}\times(n+1)=\frac{1}{n!}\end{aligned}\)
const int N=1000010;
void init() {
fact[0] = 1;
for (int i = 1; i <N; i++) {
fact[i] = fact[i - 1] * i %mod;
}
inv[N - 1] = qmi(fact[N- 1], mod - 2);
for (int i = N-2; i >= 0; i--) {
inv[i] = inv[i + 1] * (i + 1) %mod;
}
}