求逆元

Posted st-lovaer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求逆元相关的知识,希望对你有一定的参考价值。

简单的来说,已知a和m,求a的逆元(如果存在的话等于1/a mod m)。

现分几种情况讨论。

1. m是素数(a<m)。

  a的逆元必然存在。两种方法求逆元,在线用拓展欧几里得算,打表用递推。

  不用费马小定理在线算逆元是因为拓展欧几里得复杂度O(logn),费马小定理复杂度O(log mod),后者比前者慢一些。

 1 #include<bits/stdc++.h>
 2 #define ll long long 
 3 #define scan(i) scanf("%d",&i)
 4 #define f(i,a,b) for(int i=a;i<=b;i++) 
 5 #define pf printf
 6 using namespace std;
 7 ll exgcd(ll a,ll b,ll &x,ll &y)//扩展欧几里得算法 
 8 {
 9     if(b==0)
10     {
11         x=1,y=0;
12         return a;
13     }
14     ll ret=exgcd(b,a%b,y,x);
15     y-=a/b*x;
16     return ret;
17 }
18 ll getinv(int a,int mod)//求a在mod下的逆元,不存在逆元返回-1 
19 {
20     ll x,y;
21     ll d=exgcd(a,mod,x,y);
22     return d==1?(x%mod+mod)%mod:-1;
23 }
24 int main(){
25     cout<<getinv(3,7);
26     return 0;
27 } 
 1 #include<bits/stdc++.h>
 2 #define ll long long 
 3 #define scan(i) scanf("%d",&i)
 4 #define f(i,a,b) for(int i=a;i<=b;i++) 
 5 #define pf printf
 6 using namespace std;
 7 const int M=10000;
 8 ll inv[M+5];
 9 void getInv(ll mod)//离线打表求逆元 
10 {
11     inv[1]=1;
12     for(int i=2;i<mod;i++)
13         inv[i]=(mod-mod/i)*inv[mod%i]%mod;
14 }
15 int main(){
16     getInv(7);
17     cout<<inv[3];
18     return 0;
19 } 

2. m不是素数

  当gcd(a,m)!=1时,a的逆元不存在。其他情况下,打表就不行了,只能在线算了。具体方法是用上面的拓展欧几里得求,复杂度O(logn),下面贴个费马小定理的板子吧~~

ll qkpow(ll a,ll p,ll mod)
{
    ll t=1,tt=a%mod;
    while(p)
    {
        if(p&1)t=t*tt%mod;
        tt=tt*tt%mod;
        p>>=1;
    }
    return t;
}
ll getInv(ll a,ll mod)
{
    return qkpow(a,mod-2,mod);//这里本来该放的是欧拉函数,可以详见本人的其他博客~
}

 

以上是关于求逆元的主要内容,如果未能解决你的问题,请参考以下文章

线性求逆元

求逆元

AcWing 876. 快速幂求逆元

数论——快速幂,模运算及快速幂求逆元

求逆元的常用方法

求逆元