乘法逆元、扩展欧几里得算法、二元一次方程、a的n次方取余

知识点:乘法逆元,逆元的求法,二元一次方程求通解,a的n次方求余数

一,乘法逆元


乘法逆元的概念类似于倒数( ax=1,a1=x ),不过是在取余数的情况下的倒数。
如果 (a×x)%p=1 ,则称x是a模p的逆元。另一种记法: ax=1( mod p) ,即等式两边去膜 p 运算。显然 x 有无限多个(如果有)。


p,a=xp+a%p,b=yp+b%pa+b=(x+y)p+a%p+b%pab=(xy)p+a%pb%pa×b=xyp2+(x+y)p+a%p×b%p(a+b)%p=((a%p)+(b%p))%pa+b=(a%p)+(b%p)  ( mod p)(ab)%p=((a%p)(b%p))%pab=(a%p)(b%p)  ( mod p)(a×b)%p=((a%p)×(b%p))%pa×b=(a%p)×(b%p)  ( mod p)xy

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5685
逆元的作用:已知 F%pa%p 的值,求 (Fa)%p (我们不知道 Fa 的值,且 F%a=0 )。


apb(ab)%p=1[Fa×(ab)]%p=[(Fa)%p×(ab)%p]%p=(Fa)%p[Fa×(ab)]%p=[F×b]%p=[(F%p)×(b%p)]%p(b%p)


a p 的乘法逆元 b ,相当于模 p 运算中的 a1
p 运算中,乘以 b 相当于除以 a ,即乘以 a1

a×b=a×a1=1 ( mod p)[Fa]%p=[F×(1a)]%p=[F×a1]%p=[F×b]%p[Fa×b]%p=[Fa×a1]%p=F%p

逆元的存在性质:当 ap 互素的时候,逆元才存在解,如果不互素则无解(这里说的都是整数解)。显然如果p是素数(质数),那么 1 p1 的之间的数都存在模 p 的乘法逆元(质数和任何小于它的正整数都互质)。证明如下:
apap1c使a=ca1,p=cp1apb(ab)%p=1ab=xp+1abxp=1c(a1bxp1)=1a1bxp1=1c

二,求逆元


下面该学习如何求解乘法逆元

暴力破解:

档模 p 比较小的时候,我们可以枚举 1p1 ,判断 ax=1 ( mod p) 即可。如果有逆元,那么 1p1 一定存在逆元。因为任何大于p的逆元都可以写成 x=yp+x%p ,由 ax=ayp+a(x%p)=a(x%p)=1( modp) 。所以 x%p a 关于模 p 的逆元,且 x%p 小于 p

扩展欧几里得算法:

首先要了解欧几里得算法,也就是辗转相除法, gcd(a,b)=gcd(b,a%b) ,每次迭代问题规模都会减小,算法复杂度是 log n 。扩展欧几里得算法是利用辗转相除法的逆过程来得到乘法逆元的过程。求解 ax=1( mod p) ,相当于求解 ax=py+1ax+py=1 ,其中 xy 为整数。前面说过, ap 互素才有乘法逆元,所以 gcd(a,p)=1 ,所以相当于求解 ax+py=gcd(a,p)


gcd(a,p)gcd(p,a%p)ax+py=gcd(a,p)=1px1+(a%p)y1=gcd(p,a%p)=1x1y1xyax+py=gcd(a,p)=1=gcd(p,a%p)=px1+(a%p)y1ax+py=px1+(a%p)y1=px1+(a(a/p)p)y1=ay1+p(x1(a/p)y1)x=y1y=x1(a/p)y1ax+py=gcd(a,p)px1+(a%p)y1=gcd(p,a%p)gcd(a,p)xn+0yn=gcd(a,p)xn=1yn=0退xy


上述过程求解ax+py=gcd(a,p)的过程,并不要求gcd(a,p)一定等于1。由上述过程 ,我们可以推广得到求解任意二元一次方程ax+by=c的解

ax+by0=gcd(a,b)x0=x(cgcd(a,b))y0=y(cgcd(a,b))x=x0+bgcd(a,b)ty=y0agcd(a,b)ttax+by=ax0+by0+abgcd(a,b)tbagcd(a,b)t=ax0+by0

需要注意的一点是只有当 c%gcd(a,b)=0 时,方程 ax+by=c 才有整数解证明如下
ax+by=gcd(a,b)(ax+by)=cxyabcgcd(a,b)


扩展欧几里得算法代码如下:

int exgcd(int a, int b, int &x, int &y)
{
    if(b==0){
        x = 1;
        y = 0;
        return a;
    }else{
        int _gcd = exgcd(b,b%a,x,y);
        int tmp = x - (a/b)*y;
        x = y;
        y = tmp;
        return _gcd;
    }
}
x = (x % p + p) % p; // 通常需要求解最小的正整数逆元解ax=1(mod p)
// 再次提醒a和p互素,即gcd(a,p) = 1

费马小定理:

费马小定理:假如p是质数,且 gcd(a,p)=1 ,那么 ap11 ( mod p) ,即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

ap1=1 ( mod p) 很容易得到 aap2=1 ( mod p) ,那也就是 a 的逆元是 ap2

需要注意的是需要判断 ap 是否互素,如果用gcd来判断的话,那还不如直接用扩展欧几里得算法。

O(n)求1~n逆元表:

由前面可知,当 p 为素数时, 1p1 都存在模 p 的乘法逆元。
采用递推的方法来求解所有 1p1 的逆元。如下:

a=1a1a1p%a+a(p/a)=pa(p/a)=p%a ( mod p)p%a(p%a)1a(p/a)(p%a)1=1 ( mod p)a[(p/a)(p%a)1]=1 ( mod p)a(p/a)(p%a)1p%aa(p%a)11p1

也注意上面求出来的逆元是负数,很多时候需要转化为正整数,而且是最小的正整数逆元。
a[(p/a)(p%a)1]=1 ( mod p)a[[p(p/a)](p%a)1]=1 ( mod p)[[p(p/a)](p%a)1]%p

代码如下:

const int p = 13;
int inv[p+2];
inv[1] = 1;
for (int i = 2;i < p;i++)
    inv[i] = ((p - p / i)*inv[p%i]) % p;

对于1到p的都只存在一个小于p的逆元,为什么?

apgcd(a,p)1ax+py=1x=x0+pgcd(a,p)t=x0+ptxp

三,a的n次方取余


如求 20172017%1777 或者 2100%9973 的值:

a×b=(a%p)×(b%p)  ( mod p)20172017%1777={20171008×20171008×2017}%177720171008%177720171008%1777={2017504×2017504×1}%1777ab%p={(ab/2%p)2×ab%2}%plog n

代码如下:

long long remainder_of_an_exponential_recur(int a, int b, int c)
{  // 递归求 (a^b)%c
    if (b == 0)
        return 1;

    long long tmp = remainder_of_an_exponential_recur(a, b >> 1, c);
    if (b & 1)
        return (tmp*tmp*a) % c;
    else
        return (tmp*tmp) % c;
}

long long remainder_of_an_exponential_loop(int a, int b, int c)
{  // 递推求 (a^b)%c
    long long res = 1;
    long long tmp = a;
    while (b)
    {
        if (b & 1) res = (res*tmp) % c;
        tmp = (tmp*tmp) % c;
        b >>= 1;
    }
    return res;
}

如果除数是 2i ,求余数。这个比较简单 a%2 也就是求 a 的二进制表示方式中的最后一位的值。 a%2=a%(21)=a & 20=a & 1 a%8 也就是求 a 的二进制表示方式中的最后三位的值。 a%8=a%(23)=a & (231)=a & 7 。以此类推 a%(2i)=a & (2i1)


最后一个需要说的是公式: ab%p=a%(b×p)b%pa%b=0 。这个公式一般都是在无法计算得到 a 的情况下使用的,这个公式当然也可以两边乘以 b 的逆元。这个公式画图理解比较好,如下所示:
乘法逆元、扩展欧几里得算法、二元一次方程、a的n次方取余_第1张图片

在ALL X问题中:http://acm.hdu.edu.cn/showproblem.php?pid=5690。
要求检验一个全由 x 组成的 m 位数字 F(x,m) 是否可以满足等式 F(x,m) mod k=c

既可以利用余数有限重复循环的方法,即按照除法的方法依次计算余数,如果余数重复,那么就开始进入了循环,而余数的个数是有限的,小于k个。这和求 a/b 的小数表示形式是一样的(它是无限的添加0,本题中是无限的添加x)。

另一种方法是求解 F(x,m) ,容易知道 F(x,m)=x×10m19 ,那么 F(x,m) mod k=[(x%k)×10m19%k]%k ,相当于求解 10m19%k ,利用上述公式可以得到 10m19%k=(10m1)%(9k)9%k=[10m%(9k)]19%k 。而 [10m%(9k)] 可以利用a的n次方取余的方法来求解。

an ,可以用快速幂乘,a可以是矩阵。
an=an/2an/2,n
a^{n}=a^{n/2}*a^{n/2}*ahttps://www.baidu.com/s?ie=UTF-8&wd=快速幂乘&tn=98012088_4_dg&ch=10  
,n是奇数数

参考:
http://blog.csdn.NET/tsaid/article/details/7365936
http://www.cnblogs.com/ka200812/archive/2011/09/02/2164404.html
https://wenku.baidu.com/view/c1b06ea60029bd64783e2c63.html
http://blog.csdn.net/stcyclone/article/details/52081822

你可能感兴趣的:(乘法逆元、扩展欧几里得算法、二元一次方程、a的n次方取余)