乘法逆元

乘法逆元简介

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;
	}
}
posted @ 2023-12-03 22:30  White_Sheep  阅读(33)  评论(0编辑  收藏  举报