逆元相关知识

逆元相关知识

乘法逆元(mod 在C++里是%)

定义:
满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元。

为什么要有乘法逆元呢?
当我们要求 a b % p \frac{a}{b}\%p ba%p的值,且 a a a b b b都很大,无法直接求得 a b \frac{a}{b} ba的值,必须在之前mod时(因为 a b % p \frac{a}{b}\%p ba%p不等于 a % p b % p \frac{a\%p}{b\%p} b%pa%p),我们就要用到乘法逆元。

我们可以通过求 b b b关于 p p p的乘法逆元 k k k,将 a a a乘上 k k k再模 p p p,即 a ∗ k % p a*k\%p ak%p。其结果与 a b % p \frac{a}{b}\%p ba%p等价。
也就是 k = b − 1 ( m o d p ) k=b^{-1} (mod p) k=b1(modp)

证:(其实很简单。。。)

  • 根据bk≡1 (mod p)有bk=p*x+1。
  • k=(p*x+1)/b。
  • 把k代入(a*k)%p,得:
  • (a*(p*x+1)/b)%p
  • =((apx)/b+a/b)%p
  • =[((apx)/b)%p +(a/b)]%p
  • =[(p*(a*x)/b)%p +(a/b)]%p
  • //p*[(a*x)/b]%p=0
  • 所以原式等于:(a/b)%p

根据欧几里德算法

代码如下:

void Exgcd(int a,int b,int &x,int &y){if(!b) x=1,y=0;else Exgcd(b,a%b,y,x),y-=a/b*x;}
int main(){
    cin>>a>>b>>p;//(a/b)%p
	Exgcd(b,p,x,y);
	int ni=(x+p)%p;//防止出现负数
	printf("%d就是逆元\n",ni);
	return 0;
}

费马小定理求逆元

a p − 1 = 1 ( m o d p ) a^{p-1}=1(mod p) ap1=1(modp) ( p p p是素数)

那么 a / b a/b a/b关于 p p p的逆元就是 b p − 2 b^{p-2} bp2(因为 b p − 2 = 1 b b^{p-2}=\frac{1}{b} bp2=b1)

快速幂求一下就可以了,但是如果p不是素数,只能用exgcd求逆元(或没有逆元)。


线性求逆元

求i的逆元。

可得p%i+(p/i)*i=p

  • 令a=p%i,b=p/i;
  • a+b*i=p
  • a+b*i≡0(mod p)
  • b*i≡-a(mod p)
  • i^-1=-b/a

所以i的逆元:-(p/i)*(p%i)^-1

这样就可以O(n)求出所有逆元了

代码如下:

(因为1^(-1)=1,所以初始化inv[1]=1)
for(inv[1]=1,i=2;i<=n;i++) inv[i]=(p-p/i)*inv[p%i]%p;
所以最后O(1)出答案。
  • 2
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:终极编程指南 设计师:CSDN官方博客 返回首页
评论

打赏作者

XSamsara

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值