• 逆元总结


    一、快速幂求逆元

      1、直接用费马小定理 $a^{(m - 1)}equiv 1(mod m)   < = >     a^{(m - 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;
    }

      

  • 相关阅读:
    Oracle 服务命名(别名)的配置及原理,plsql连接用
    AdHoc发布时出现重复Provisioning Profile的解决方案
    xcode5时代如何设置Architectures和Valid Architectures
    C# WinForm 导出导入Excel/Doc 完整实例教程[使用Aspose.Cells.dll]
    DataTable的数据批量写入数据库
    高中生活--第7篇–我为什么不交作业
    ITFriend网站内测公测感悟
    网站推广第一周总结和反思
    第一次当面试官
    技术人才的出路在哪里,5种选择和2种思路
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/10805619.html
Copyright © 2020-2023  润新知