求乘法逆元的5种方法
求
正
整
数
a
关
于
1
模
p
的
的
乘
法
逆
元
,
即
求
满
足
a
x
≡
1
(
m
o
d
p
)
的
正
整
数
解
x
。
求正整数a关于1模p的的乘法逆元,即求满足ax≡1(mod\ p)的正整数解x。
求正整数a关于1模p的的乘法逆元,即求满足ax≡1(mod p)的正整数解x。
文章目录
一、 扩 展 欧 几 里 得 算 法 ( O ( l o g P ) ) 扩展欧几里得算法(O(logP)) 扩展欧几里得算法(O(logP))
将 a x ≡ 1 ( m o d p ) 转 化 为 解 方 程 a x + p y = 1 的 正 整 数 解 x 。 将ax≡1(mod\ p)转化为解方程ax+py=1的正整数解x。 将ax≡1(mod p)转化为解方程ax+py=1的正整数解x。
前 提 条 件 : a 与 p 互 质 , 此 时 解 唯 一 。 前提条件:a与p互质,此时解唯一。 前提条件:a与p互质,此时解唯一。
代码:
int exgcd(int a,int b,int &x,int &y) //ax≡1(mod p)
{ //ax+py=1
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
int main()
{
int p,x,y;
p=mod;
for(int a=1;a<=20;a++) //求出1~20的逆元
{
exgcd(a,p,x,y);
cout<<(x+p)%p<<endl;
}
}
二 、 费 马 小 定 理 ( O ( l o g P ) ) 二、费马小定理(O(logP)) 二、费马小定理(O(logP))
前 提 条 件 : p 为 质 数 前提条件:p为质数 前提条件:p为质数
则 有 a p − 1 ≡ 1 ( m o d p ) 则有a^{p-1}≡1(mod\ p) 则有ap−1≡1(mod p)
即 a ⋅ a p − 2 ≡ 1 ( m o d p ) , 即a·a^{p-2}≡1(mod\ p), 即a⋅ap−2≡1(mod p),
a p − 2 即 逆 元 。 通 过 快 速 幂 可 解 。 a^{p-2}即逆元。通过快速幂可解。 ap−2即逆元。通过快速幂可解。
三 、 欧 拉 定 理 求 逆 元 ( O ( P ) ) 三、欧拉定理求逆元(O(\sqrt{P})) 三、欧拉定理求逆元(O(P))
欧 拉 定 理 : 若 p , a 为 正 整 数 , 且 p , a 互 质 , 则 : 欧拉定理:若p,a为正整数,且p,a互质,则: 欧拉定理:若p,a为正整数,且p,a互质,则:
a ϕ ( p ) ≡ 1 ( m o d p ) a^{\phi(p)}≡1(mod\ p) aϕ(p)≡1(mod p)
当 p 为 质 数 时 , 即 费 马 小 定 理 。 当p为质数时,即费马小定理。 当p为质数时,即费马小定理。
因 此 , 我 们 可 以 对 p 先 求 出 欧 拉 函 数 ϕ ( p ) , 再 用 快 速 幂 求 出 乘 法 逆 元 为 a ϕ ( p ) − 1 。 因此,我们可以对p先求出欧拉函数\phi(p),再用快速幂求出乘法逆元为a^{\phi(p)-1}。 因此,我们可以对p先求出欧拉函数ϕ(p),再用快速幂求出乘法逆元为aϕ(p)−1。
可 用 定 义 求 欧 拉 函 数 , 时 间 复 杂 度 O ( p ) 可用定义求欧拉函数,时间复杂度O(\sqrt{p}) 可用定义求欧拉函数,时间复杂度O(p)
代码:
ll get_euler(ll C) //定义求欧拉函数
{
ll res=C;
for(int i=2;i<=C/i;i++)
if(C%i==0)
{
while(C%i==0) C/=i;
res=res/i*(i-1);
}
if(C>1) res=res/C*(C-1);
return res;
}
亦 可 用 线 性 筛 筛 出 [ 1 , n ] 内 的 欧 拉 函 数 。 亦可用线性筛筛出[1,n]内的欧拉函数。 亦可用线性筛筛出[1,n]内的欧拉函数。
四 、 递 推 四、递推 四、递推
求 区 间 [ 1 , n ] 的 逆 元 , 时 间 复 杂 度 O ( n ) 。 求区间[1,n]的逆元,时间复杂度O(n)。 求区间[1,n]的逆元,时间复杂度O(n)。
代码:
int inv[N];
inv[1]=1;
for(int i=2;i<=20;i++)
inv[i]=(long long)(mod-mod/i)*inv[mod%i]%mod;
五 、 递 推 求 阶 乘 逆 元 五、递推求阶乘逆元 五、递推求阶乘逆元
先 求 出 n ! 的 逆 元 , 再 倒 序 递 推 。 先求出n!的逆元,再倒序递推。 先求出n!的逆元,再倒序递推。
代码:
void init()
{
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
inv[n]=quick_pow(fac[n],mod-2,mod); //求出最大项阶乘的逆元
for(int i=n-1;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod; //递推得到所有阶乘的逆元
}