码迷,mamicode.com
首页 > 其他好文 > 详细

求逆元

时间:2019-10-28 09:13:34      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:方法   ace   拓展欧几里得   col   out   get   scanf   color   std   

简单的来说,已知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);//这里本来该放的是欧拉函数,可以详见本人的其他博客~
}

 

求逆元

标签:方法   ace   拓展欧几里得   col   out   get   scanf   color   std   

原文地址:https://www.cnblogs.com/St-Lovaer/p/11750047.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!