• 逆元 x


    逆元:

    丢线

    1.首先定义:

      若存在正整数a,x,m,且满足ax≡1(mod m),则称a是x的乘法逆元,或称x是a的乘法逆元.

    Eg:

      模7意义下,3的乘法逆元是5(或模7意义下,5的乘法逆元是3)

      1)3*1%7=3%7=3   =/=1(x)

      2)3*2%7=6%7=6   =/=1(x)

      3)3*3%7=9%7=2   =/=1(x)

      4)3*4%7=12%7=5 =/=1(x)

      5)3*5%7=15%7=1 ==1 (√)

            ||

            ||

            ||

            v

      模7意义下,3的乘法逆元是5(或模7意义下,5的乘法逆元是3)

    其他的求乘法逆元的方式与此类似。

    2.乘法逆元存在性定理 

    我们来考虑一下同余方程:

        ax ≡ 1(mod m)

    若a 与m 互质, 则一定存在一个正整数解x, 满足x < m.
    若a 与m 不互质, 则一定不存在正整数解x.

    意思也就是说, 互质与乘法逆元存在互为充要条件.

    3.求法

      ①欧拉定理/费马小定理

    •   3.1欧拉定理
      •   3.1.1欧拉定理公式:

                aφ(p) ≡ 1(mod p)

              (是对于任意互质的a,p恒成立的)

      •   3.1.2推论

            a*aφ(p)-1 ≡ 1(mod p)

            只有通过这个公式+快速幂才能够求逆元~

      •   3.1.3欧拉函数定义

            欧拉函数φ(n)表示小于等于n且与n互质的正整数的个数

              Eg:φ(6)=2,φ(7)=6,φ(1)=1

           欧拉函数是一个数论函数, 也是一个积性函数, 可以线性筛出.

    • 3.1.4欧拉函数公式:

        若令n=∏ki=1 pi ci为n的质因子分解形式,则有

                  k   pi-1

              φ(n)=n∏  ----------

                 i=1    pi

    欧拉函数可以利用容斥原理在O(sqrt(n))的时间复杂度上界中求出

      ②线性求逆元

      ③拓展欧几里得

    逆元一般用拓展欧几里得算法来求得,如果为素数(常用素数有:998244353,1000000007),则经常根据费马小定理(用于降低题目的难度)得到逆元为

    其推导过程如下:                

    例:

    求如下表达式的值(已知)(|为整除号)

               

    当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果是素数,还可以用费马小定理!!!

    但是你会发现费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求互素。实际上我们还有一种通用的求逆元方法,适合所有情况。

    公式如下:

              

    现在我们来证明它,已知,证明步骤如下

              

    而对于(a/b)%m== 一个数

      1.当m是素数的时候,根据费马小定理(不懂的可以去这儿看看),直接输出b^(n-2)即可

      2.否则,就根据拓展欧几里得exgcd(b,m,x,y)

        Ps:拓展欧几里得能够保证求出的x,y满足|x|+|y|最小

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    
    using namespace std;
    int a,b,m;
    int x,y;
    
    int exgcd(int a,int b,int &x,int &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        int r=exgcd(b,a%b,x,y),tmp;
        tmp=x,x=y;
        y=tmp-a/b*y;
        return r;
    }
    
    int fastpow(int a,int p)
    {
        int bb=a;int ans=1;
        while(p!=0)
        {
            if(p%2==1)ans=ans*bb;
            bb=bb*bb;
            p=p/2;
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d%d%d",&a,&b,&m);
        for(int i=1;i<=sqrt(m);i++)
        {
            if(m%i==0)
            {
                int ans=exgcd(b,m,x,y);
                printf("%d",(a*ans)%m);
                return 0;    
            }
        }
        printf("%d",fastpow(b,m-2));
    }

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    音频可视化
    accunulate
    node
    js 中编码(encode)和解码(decode)的三种方法
    ES6高阶 同步和异步 回调地狱 promise async和await
    区间dp
    树形dp1
    背包dp(多重)
    树形dp
    背包dp(完全)
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/6880386.html
Copyright © 2020-2023  润新知