逆元总结

Posted wtsruvf

tags:

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

一、快速幂求逆元

  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;
}

 

  

 

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

逆元总结

各种求逆元方法总结[转]

(数论)简单总结求逆元的几种方法

总结四种逆元的求法

同余&逆元简单总结

乘法逆元 学习总结