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

逆元总结

时间:2019-05-03 18:45:05      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:扩展欧几里得   ret   效率   适用于   ==   gcd   int   exgcd   算法   

一、快速幂求逆元

  1、直接用费马小定理 $a^{(p - 1)}\equiv 1(mod m)   < = >     a^{(p - 2)}\equiv a^{-1}(mod m)$    当m为素数时

  2、当m不为素数时  已知m的欧拉函数满足 $a^{\phi (m)}\equiv 1(mod m)     < = >      a^{\phi (m) - 1}\equiv a^{-1}(mod m)$

  所以可以直接 用$a^{\phi (m) - 1}\equiv a^{-1}(mod m)$

  先用gcd判断a和m是否互质  若不互质 则不存在模m下的逆元

int prime[maxn+10], phi[maxn+10];
bool vis[maxn+10];
int ans;
void get_phi()
{
    ans = 0;
    phi[1] = 1;
    for(int i=2; i<=maxn; i++)
    {
        if(!vis[i])
        {
            prime[++ans] = i;
            phi[i] = i - 1;
        }
        for(int j=1; j<=ans; j++)
        {
            if(i * prime[j] > maxn) break;
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0)
            {

                phi[i * prime[j]] = phi[i] * prime[j]; break;
            }
            else
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
    }
}

LL q_pow(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;
}
LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a % b);
}


int main()
{
    get_phi();

    int T;
    rd(T);
    while(T--)
    {
        LL n, m;
        cin >> n >> m;
        if(gcd(n, m) != 1)
            cout << "Not Exist" << endl;
        else
        {
            int d = q_pow(n, phi[m] - 1, m);
            cout << d << endl;
        }
    }
    
    return 0;
}

 

二、exgcd求逆元

给定模数m,求a的逆相当于求解ax=1(mod m)
这个方程可以转化为ax-my=1
然后套用求二元一次方程的方法,用扩展欧几里得算法求得一组x0,y0和gcd
检查gcd是否为1
gcd不为1则说明逆元不存在
若为1(a与m互质),则调整x0到0~m-1的范围中即可

PS:这种算法效率较高,常数较小,时间复杂度为O(ln n)
适用范围:只要存在逆元即可求,适用于个数不多但是mod很大的时候,也是最常见的一种求逆元的方法。

void extgcd(ll a,ll b,ll& d,ll& x,ll& y)
{
    if(!b)
        { d=a; x=1; y=0;}
    else
    {
        extgcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}
void inverse(ll a,ll n) 
{
    ll d,x,y;
    extgcd(a,n,d,x,y);
    if(d == 1)
    {
        x = (x % n + n) % n;
        if(x == 0)
            x += n;
        cout << x << endl;
    }
    else  //不存在
        cout << "Not Exist" << endl;
}

 

  

 

逆元总结

标签:扩展欧几里得   ret   效率   适用于   ==   gcd   int   exgcd   算法   

原文地址:https://www.cnblogs.com/WTSRUVF/p/10805619.html

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