逆元求法 -csdn博客

参考博客:欧几里得算法和逆元


首先对于什么是逆元呢? 逆元存在的条件是在取模运算中,一个数的逆元就是这个数和他的逆元相乘后的乘积取模后的结果为1,既ax=1(mod p),则称x为a关于模p的逆元。因此这个特性可以让我们把数据比较大的除法运算转换算为乘法运算的取模。因此,逆元也是一个很重要的一个知识。

-逆元求法:

  1. 扩展欧几里得算法:

首先对与式子 ax+by=gcd(a,b); 对于该公式可以用扩展欧几里得公式求得。如果gcd(a,b)=1时,对公式两边同时取模b,则有ax≡1(mod b),所以x为a关于模b的逆元。附上代码:

void exgcd(int a,int mod,int &x,int &y)
{
	if(mod==0){
		x=1,y=0;return ;
	}else
	{
		exgcd(mod,a%mod,y,x);
		y-=a/mod*x;
	}
}
int inv(int a)
{
	int x,y;
	exgcd(a,p,x,y);
	return (x+mod)%mod;
}

2.费马小定理:

费马小定理:加入p是素数,且a和p互素,则存在以下公式 a^(p-1)≡1(mod p);因此a^(p-2)即为a关于p的逆元。不过由于我们做题的时候一般p会比较大,因此用快速幂的可能行会更高。

//快速幂求a关于MOD的逆元
	int inv(int a){
	int p=MOD-2;int ans=1;
	while(p>0){
		if(p&1)ans=ans*a%MOD;
		a*=a;
		p>>=1;
		a%=MOD;
	}
	return ans;
}

3.线性求逆元:

线性逆元的递推公式:inv[i]=inv[Mmodi]×(M−M/i)modM
其中:i < M;
证明:
设 M = ki + b;
=> k = M / i, b = M mod i;
=> ki + b = 0 ( mod M);
=> ki = -b ( mod M);
=> 1 / ki = -1 / b ( mod M);
=> 1 / i = -k / b (mod M);
=> inv( i ) = inv( M mod i ) * ( M - M / i ) % M;
代码:

int inv(int a) { 
    return a == 1 ? 1 : (MOD - MOD / a) * inv(MOD % a) % MOD;  
}  

小结:

扩展欧几里得:要求a,p互为质数。时间复杂度O (log max( a ,p));
费马小定理:要求a,p互为质数,且p为素数。因此要求更高时间复杂度O (log p);
线性递推:由于是递推,因此如果是求n以内所有数的逆元的时间复杂度为O(n);
因此,如果是求一个数的逆元用扩展欧几里得算法会更好,如果求一个区间内很多数的逆元用线性递推更好。而且代码非常简单_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值