zoukankan      html  css  js  c++  java
  • 逆元的认知与应用——处理除数很大的时候

    1.什么是逆元

    当求解公式:(a/b)%m 时,因b可能会过大,会出现爆精度的情况,所以需变除法为乘法:

    设c是b的逆元,则有b*c≡1(mod m);///b*c%m=1%m;

    则(a/b)%m = (a/b)*1%m = (a/b)*b*c%m = a*c(mod m);

    即a/b的模等于a*b的逆元的模;

    逆元就是这样应用的.

    2.求逆元的方法。

    (1).费马小定理

    在是素数的情况下,对任意整数都有。 
    如果无法被整除,则有。 
    可以在为素数的情况下求出一个数的逆元,,即为逆元。

    题目中的数据范围1<=x<=10^9,p=1000000007,p是素数;

    所以x肯定就无法被p整除啊,所以最后就得出x^(p-2)为x的逆元啦。

    但是似乎还有个问题?如何判断a是否有逆元呢? 

    检验逆元的性质,看求出的幂值x与a相乘是否为1即可

    当p比较大的时候需要用快速幂求解

    复杂度O(logn);

    const int mod = 1000000009;
    long long qpow(long long a,long long b)
    {
        if(b<0)
            return 0;
        long long res=1;
        a%=mod;
        while(b)
        {
            if(b & 1)
                res=(res*a)%mod;
            b >>= 1;
            a=(a*a)%mod;
        }
        return res;
    }
    long long inv(long long a)
    {
       return  qpow(a,mod-2);
    }
    View Code

    (2) 扩展欧几里得

    给定模数m,求a的逆相当于求解ax=1(mod m)

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

    PS:这种算法效率较高,常数较小,时间复杂度为O(ln n)

    可扩展欧几里得求逆元ax≡1(mod n)其中a,n互质;

    ll ecgcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        else 
        {
            ll r=ecgcd(b,a%b,x,y);
            ll temp=x;
            x=y;
            y=y-a/b*temp;
            return r;
        }
    }
    ll inv(ll a,ll n)
    {
        ll x,y;
        exgcd(a,n,x,y);
        x = (x%n+n)%n;
        return x;
    }
    View Code

    (3)逆元打表法

    有时会遇到这样一种问题,在模质数p下,求1~n逆元 n< p(这里为奇质数)。可以O(n)求出所有逆元,有一个递推式如下

                       

    它的推导过程如下,设,那么

           

    对上式两边同时除,进一步得到

           

    再把替换掉,最终得到

           

    初始化,这样就可以通过递推法求出1->n模奇素数的所有逆元了。

    另外有个结论的所有逆元值对应中所有的数,比如,那么对应的逆元是

    const int n=le5+5;
    int inv[n];
    void inverse(int n,int p)
    {
        inv[1]=1;
        for(int i=2 ; i<=n ;i++)
        {
            inv[i]=(ll)(p-p/i)*inv[p%i]%p;
        }
    }
    View Code

    补充习题练手处:https://blog.csdn.net/acdreamers/article/details/8220787

  • 相关阅读:
    Spring中的事务传播行为与隔离级别
    redis分布式共享锁模拟抢单的实现
    synchronized关键字修饰非静态方法与静态方法的区别
    docker安装Tensorflow并使用jupyter notebook
    python 图像处理(4):图像的绘制
    python 图像处理(3):图像数据类型及颜色空间转换
    python 图像处理 (2):图像像素的访问与裁剪
    python 读取图像的几种方法
    python 图像处理:图像的读取、显示与保存
    NLP 正向、逆向 分词
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/8972903.html
Copyright © 2011-2022 走看看