博客
关于我
乘法逆元
阅读量:402 次
发布时间:2019-03-06

本文共 2408 字,大约阅读时间需要 8 分钟。

1定义

乘法逆元,是指数学领域群G中任意一个元素a,都在G中有唯一的逆元a‘,具有性质a×a'=a'×a=e,其中e为该群的单位元。

定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1
证明: 首先证明充分性 如果gcd(a,p) = 1,根据欧拉定理,aφ(p) ≡ 1 mod p,因此 显然aφ(p)-1 mod p是a的模p乘法逆元。 再证明必要性 假设存在a模p的乘法逆元为ba ≡ 1 mod p 则 1 = ba - qp
根据贝祖定理,这个式子有整数解的充要条件是a和p的最大公约数整除1,故必须要满足gcd(a,p) = 1
举个例子,在模10的意义下,3的逆元为7,因为3
7与1在模10的意义下同余。

2.计算

下面的逆元均指在模运算下的逆元。

2.1费马小定理

根据费马小定理,如果p是质数,有\(a^{p-1}\equiv1(mod p)\),其中a是整数,所以\(a^{p-2}\)为a的逆元,用快速幂即可,注意取模,这个逆元在模p状态下唯一。

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define dd double#define ll long long#define ull unsigned long long#define N 110#define M 20using namespace std;inline ll ksm(ll a,ll b,ll m){ ll res=1; while(b){ if(b&1) res=(res*a)%m; a=(a*a)%m; b>>=1; } return res%m;}int main(){ ll n,p; scanf("%lld%lld",&n,&p); for(int i=1;i<=n;i++){ printf("%lld\n",ksm(i,p-2,p)); }}

2.2 扩展欧几里得算法

根据扩展欧几里得算法,知道\(a*x\equiv1(mod p)\)(其实等价于\(k*p-a*x=1\))有解,那么可以通过扩展欧几里得算法求出。这里不再赘述。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define dd double#define ll long long#define ld long double#define ull unsigned long long#define N number#define M numberusing namespace std;inline ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1; y=0; return a; } ll gcd=exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; return gcd;}int main(){ ll a,b; scanf("%lld%lld",&a,&b); ll x,y; exgcd(a,b,x,y); printf("%lld",(x%b+b)%b);}

2.3递推求逆元

首先,我们用\(a^{-1}\)表示a的逆元,易知\(1^{-1}=1\equiv1(mod p)\),所以1为1的逆元

还有递推公式证明:设\(q*k+r=p\)
则:\(q*k+r\equiv0(mod p)\)
\(k*r^{-1}+q^{-1}\equiv0(mod p)\)
\(q^{-1}\equiv{-k*r^{-1}}(mod p)\)
\(q^{-1}\equiv{(p-k)*r^{-1}}(mod p)\)
由此得出递推公式:inv[i] = (p - p / i) * inv[p % i] % p;(设inv[i]为i的逆元)
代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define dd double#define ll long long#define ull unsigned long long#define N 4000010#define M 20using namespace std;int inv[N];int main(){ ll n,p; scanf("%lld%lld",&n,&p); inv[1]=1; printf("%d\n",inv[1]); for(int i=2;i<=n;i++){ inv[i]=(p-p/i)*inv[p%i]%p; printf("%d\n",inv[i]); } return 0;}

转载地址:http://zjdkz.baihongyu.com/

你可能感兴趣的文章
nodeJS实现识别验证码(tesseract-ocr+GraphicsMagick)
查看>>
玩玩小爬虫——试搭小架构
查看>>
AS与.net的交互——加载web上的xml
查看>>
Javascript之旅——第八站:说说instanceof踩了一个坑
查看>>
Javascript之旅——第九站:吐槽function
查看>>
Javascript之旅——第十一站:原型也不好理解?
查看>>
Sql Server之旅——第十站 看看DML操作对索引的影响
查看>>
十五天精通WCF——第二天 告别烦恼的config配置
查看>>
双十一来了,别让你的mongodb宕机了
查看>>
asp.net mvc 之旅 —— 第六站 ActionFilter的应用及源码分析
查看>>
Tomcat 热部署
查看>>
深入解析 HTTP 缓存控制
查看>>
深入浅出访问者模式
查看>>
深入探索Android热修复技术原理读书笔记 —— 热修复技术介绍
查看>>
百度前端技术学院task16源代码
查看>>
解析js中( ( ) { } ( ) )的含义
查看>>
js设计模式总结5
查看>>
Python大神编程常用4大工具,你用过几个?
查看>>
一文带你了解图神经网络
查看>>
9个常用ES6特性归纳(一般用这些就够了)
查看>>