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

来源:互联网 发布:网络公开课IT 编辑:程序博客网 时间:2024/05/22 23:58

知识点:乘法逆元,逆元的求法,二元一次方程求通解,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)


ap的乘法逆元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是素数(质数),那么1p1的之间的数都存在模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%pa关于模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&1a%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的逆元。这个公式画图理解比较好,如下所示:
这里写图片描述

在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是奇数数
<script type="math/tex" id="MathJax-Element-1408">a^{n}=a^{n/2}*a^{n/2}*ahttps://www.baidu.com/s?ie=UTF-8&wd=快速幂乘&tn=98012088_4_dg&ch=10 ,n是奇数数</script>

参考:
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