数论——乘法逆元(快速幂求法)及模运算

一、快速幂

原理:

  快速幂的原理十分简单。

  ak=a2^0*a2^1*a2^2*…a2^x,其中k=20+21+22+…+2x

  这显然是正确的。因为任何一个数都可以表示成二进制。

  接下去利用位运算实现即可。

代码实现

  模板题链接:快速幂

  代码模板如下:时间复杂度O(logk)

int qmi(int a,int k,int p)
{
    int res=1%p;
    while(k)
    {
        if(k&1)res=(long long)res*a%p;
        a=(long long)a*a%p;
        k>>=1;
    }
    return res;
}

  值得一提的是,以上代码在过程中取模,是基于模运算的运算规则。

  模运算有一些很好的性质,以下列举四条:

  •  (a + b) % p = (a % p + b % p) % p 
  •  (a - b) % p = (a % p - b % p + p) % p 
  •  (a * b) % p = (a % p * b % p) % p 
  •  (a^b) % p = ((a % p)^b) % p 

二、快速幂求逆元

乘法逆元的定义

 若整数b,m互质,并且b|a,则存在一个整数x,使得a/bax(mod m),则称x为b的模m乘法逆元,记为b1(mod m)

b存在乘法逆元的充要条件是b与模数m互质。当模数m为质数时,bm2即为b的乘法逆元。

  因为在模运算中,并没有除法的性质,即没有(a/b)%p≠((a%p)/(b%p))%p,而乘法逆元便可以帮助我们将其转化成乘法形式:a/b % m=ax % m。

  由乘法逆元的定义我们可以推出如下结论:

∵ a/b mod p = a * b-1 mod p = a/b * b * b-1 mod p

∴ b * b-1 ≡ 1(mod p)

费马小定理

若p是一个质数,且整数a不是p的倍数(a与p互质),则有a p-1 ≡ 1(mod p)。

  基于这个定理,我们就可以推出如下结论:

 ∵ a p-1 ≡ 1(mod p)

∴ a * a p-2 ≡ 1(mod p)

  因此,结合乘法逆元的定义所得到的推论以及费马小定理,我们可以得到:a-1 = a p-2(mod p)。

  也就是说,当模数p为质数,且整数b不是p的倍数时(b与p互质),b的逆元即为b p-2

代码实现

  模板题链接:快速幂求逆元  

  根据上述结论,要判断b关于模数p的乘法逆元是否存在,若存在则求出之,我们便只需要计算b p-2即可。而这个计算利用快速幂便可以很快解决。

  代码如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;

int qmi(int a,int k,int p)
{
    int res=1%p;
    while(k)
    {
        if(k&1)res=(ll)res*a%p;
        a=(ll)a*a%p;
        k>>=1;
    }
    return res;

}

int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a%b==0)printf("impossible\n");
        else printf("%d\n",qmi(a,b-2,b));
    }
    return 0;
}

应用

  有了乘法逆元,我们在计数类问题中遇到(a/b)%p时,便可以转化成((a % p) * (b-1 % p)) % p来计算了,这样便防止了爆int的情况出现,当然,转化的前提是必须保证b与p互质。当p是质数时,则可以进一步转化为((a % p) * (b p-2 % p)) % p。

posted @ 2019-07-19 19:32  魑吻丶殇之玖梦  阅读(1647)  评论(0编辑  收藏  举报