浅谈乘法逆元

一.模意义下的除法

  我们在平时计算中可能遇到一种情况:$\frac{3}{4}\times 20$ 这个算式,在刚开始计算时,出现了分数(在模意义下是不允许的),但最终结果仍然是个整数,所以这个式子在模意义下依然是合法的遇到这种情况,我们能否找到一种类似于除法的操作,使其在模意义下可以代替除法?

二.逆元

  我们需要一种特殊的数,在“除以a”的时候,我们把“除以a”替换成乘这个特殊的数,依然能得到正确结果。

  在有理数下,这个“特殊的数”,显然是$\frac{1}{x}$,那么在模意义下这个“特殊的数”又是多少?

  先来看几个例子吧:

    $\frac{3}{4}\times 20\equiv 4 \: \: (mod\: \: \: 11)$

    我们可以将“除以4”替换成“乘3”,则算式变为:

    $3\times 3\times 20\equiv 4\, \, (mod\, \, 11)$

    在这个算式中的“特殊的数”就是3

 

    $\frac{4}{7}\times 14\equiv 8\: \: (mod\: \: \: 19)$

    我们可以将“除以7”替换成“乘11”,则算式变为:

    $4\times 11\times 14\equiv 8\, \, (mod\, \, 19)$

    在这个算式中的“特殊的数”就是11

  

  对于一个模数p和一个除数n,一般可以找到一个特殊的数x,可以起到除法的效果

我们称这个特殊的数为“n在模p意义下的逆元”。一个数x的逆元一般记作inv(x)。

  逆元的性质:

      对于一个x和x的逆元inv(x),满足  

         $x \times inv(x) \equiv 1\, \, (mod\, p)$

 

  问题:什么时候找不到逆元?

      显然当除数x和模数p不互质时,永远找不到x在模p意义下的逆元

三.如何找一个数的逆元?

    1.费马小定理

    当模数p为素数(质数)时,我们可以用费马小定理来求逆元。

    费马小定理:$x^{p-1}\equiv 1\, \, (mod\, \, p)$

    根据逆元的性质我们有:

        $x \times inv(x) \equiv 1\, \, (mod\, p)$

    又据费马小定理:

        $x^{p-1}\equiv 1\, \, (mod\, \, p)$

    故:

        $x \times inv(x) \equiv x^{p-1}\, \, (mod\, p)$

    式子两边同时除以x,得到:

        $inv(x) \equiv x^{p-2}\, \, (mod\, p)$

    x的p-2次方可以用快速幂来求

    Code:

#include<iostream>
#include<cstdio>
using namespace std;
inline int read(){
	register int x=0,v=1,ch=getchar();
	while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}
	return x*v;
}
inline int ksm(int x,int p,int Mod){
	register int res=1;
	while(p){
		if(p&1)res=res%Mod*x%Mod;
		p>>=1;
		x*=x%Mod;
	}
	return res;
}
int x,p;
int main(){
	x=read(),p=read();
	printf("%d\n",ksm(x,p-2,p));
	return 0;
}

    


 

   2.exgcd

    我们有 $a\times inv(a)\equiv 1\, \, (mod\, \, p)$

    已知a,p求inv(a)的值

    方程中有恒等号,可以先进行变式,得到    

        $a\times inv(a)= kp+1\, \, (mod\, \, p)$

    其中,k为任意值(因为在模意义下加上任意整数倍的模数,式子还是成立的)

    将方程移项,得到:

        $a\times inv(a)-kp=1\, \, (mod\, \, p)$

    因为k为任意值,所以将k取负值后,得到

        $a\times inv(a)+kp=1\, \, (mod\, \, p)$

    因为一个数有逆元,需要满足此数与模数互质(即满足$a\perp p $),所以方程右边可以写成

        $a\times inv(a)+kp=gcd(a,p)\, \, (mod\, \, p)$

    这样我们就将式子转化成了exgcd可以解决的问题

    Code:

#include<iostream>
#include<cstdio>
using namespace std;
inline int read(){
	register int x=0,v=1,ch=getchar();
	while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}
	return x*v;
}
#define pr pair<int,int>
#define x tmp.first
#define y tmp.second 
inline pr Exgcd(int a,int b){
	if(b==0)return pr(1,0);
	pr tmp=Exgcd(b,a%b);
	return pr(y,x-a/b*y);
}
inline void Getans(int a,int p){
	pr tmp=Exgcd(a,p);
	printf("%d\n",(x%p+p)%p);//注意exgcd可能会出负数,C++在负数%的时候还会出负数,需要特殊处理一下
}
int a,p; 
int main(){
	a=read(),p=read();
	Getans(a,p);
	return 0;
}

 


     3.线性递推逆元

    这个操作可以在O(p)的时间复杂度内处理出$\left [ 1 ,\right p-1]$中所有数在模p意义下的逆元

    递推式:$inv(i)=(p-p/i)\times inv(p\, \, mod\, \, i)\, \, mod\, \, p$

    证明过程:

      假设该式成立,则有

           $i\times inv(i)=i\times (p-\lfloor\frac{p}{i}\rfloor)\times inv(p\, \, mod\, \, i)\, \, mod\, \, p$

      变式后可得

          $i\times inv(i)=(ip-i\times\lfloor \frac{p}{i} \rfloor ))\times inv(p\, \, mod\, \, i)\, \, mod\, \, p$

      根据随时取模性质,得到

          $i\times inv(i)=(p\, \, mod\, \, i)\times inv(p\, \, mod\, \, i)\, \, mod\, \, p$

      显然,这个式子是成立的

    Code:

#include<iostream>
#include<cstdio>
using namespace std;
inline int read(){
	register int x=0,v=1,ch=getchar();
	while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}
	return x*v;
}
const int MAX=105;
int inv[MAX],p,n; 
int main(){
	n=read();
	p=read();
	inv[1]=1;
	for(register int i=2;i<=p-1;++i){
		inv[i]=(p-p/i)*inv[p%i]%p;
	}
	for(register int i=1;i<=n;++i){
		printf("%d ",inv[i]);
	}
	printf("\n");
	return 0;
}

  


有什么需要修改的地方请您留言给作者,谢谢

希望这篇文章对大家有帮助

转载于:https://www.cnblogs.com/Lates/p/11147053.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值