扩展欧几里德 中国剩余定理 合并模线性方程组

2019-04-13 15:26发布

1.1.1 扩展欧几里得

要说扩展必须先从它的非扩展版本说起,对于求两个数的最大公约数,我们有辗转相除法,其核心就是gcd(a,b)=gcd(b,a%b) (a>=b) (1)为什么呢,我们来证明一下令a=k*b+t  a%b=t ,若设dab的一个公约数,a%d==0 k*b%d==0 又因为(k*b+t)%d==0 所以t%d==0,这个d包含了ab的最大公约数,于(1)得证。有了这个作为基础我们来看下扩展欧几里得到底是个什么东东,对于这样一个不定方程ax+by=c 方程有解当且仅当 c%gcd(a,b)==0,为什么呢,因为(ax+by)%gcd(a,b)==0,得证。于是对于ax1+by1=gcd(a,b) 该方程的一组解(x1,y1) 只需都乘上c/gcd(a,b),就可以得到原方程的一组(x,y)解。我们现在只需要考虑ax1+by1=gcd(a,b).由于gcd(a,b)=gcd(b,a%b),a*x1+b*y1=gcd(a,b)=gcd(b,a%b)=b*x2+(a%b)*y2,k=a/b r=a%b a=k*b+r,r=a-k*b将其带入不定方程得a*x1+b*y1=b*x2+(a-(a/b)*b)y2=a*y2+b*(x2-(a/b)*y2) (x1=y2,y1=x2-(a/b)*y2),我们还可得到通解  xx=x1+b/gcd(a,b)*t yy=y1- a/gcd(a,b)*t  (t为任意正整数,x1,y1为一组基解),扩展欧几里得一个很大的应用就是求乘法逆元,逆元是什么?离散数学全还给老师了-_-||,定义群Gx∈G,若存在x'∈G,e是单位元,x'· x=e则称x'x左逆元 x·x'=e,则称x'x右逆元,若两者一样,则x'是x的逆元,注意在G中元素可能没有逆元。在模运算中a×b ≡1 (mod m)则bam的乘法逆元。乘法逆元1/b(mod m)存在当且仅当gcd(b,m)=1,且满足1/b (mod m)存在的b的个数为phi(m)个。下面来看下如何求逆元,对于1/a (mod n) = x 若存在,则可以写成ax %n =1 即 ax - (ax/n)*n=1 等价于 ax-ny=1,求解即可。

1.1.2 中国剩余定理

对于所有ai%mi=x方程组 (1<=i<=n),m值两两互素,且都>1,则存在解x满足上面方程组,对于另一个x' != x 满足 x' % M = x 其中M=m1*m2....*mn。这个证明参看《计算数论》p 112 - p 113 。其解得形式可以写成 x sigma( ai Mi Mi' % m) (1<=i<=n) 其中m =m1*m2...mn, Mi=m/mi ,Mi* Mi' %mi =1。 

1.1.3 合并模线性方程组

先简单介绍下线性同余方程 ax%n=b 其有解需满足(a,n)|b,且其解得个数有(a,n)个,令d=gcd(a,n) t(a/d)x % (n/d) = (b/d)的唯一解,则ax%n=bd个解为t,t+n/d,t+2n/d....t+(d-1)n/d。证明其有解过程如下:若有解,则(a,n)|b满足,设s为一个解,则as%n=b,则n|(as-b),as-b=kn(k为整数因为 (a,n)|a,(a,n)|kn,所以(a,n)|b证毕。  问题模型:给定模线性同余方程组 r[i]%a[i]=m (1均为正整数),判断是否存在最小非负整数解,为一般方程不考虑中国剩余定理的情形。先看前两个方程a1*x+r1=m a2*y+r2=m, 可以写成a*x-b*y=r2-r1 方程有解需保证(a,b)|(r2-r1),问题等价于寻求ax+by=n的解,我们利用扩展欧几里得先求得ax+by=(a,b)的一组解(x0,y0),于是(x1,y1)=(x0,y0)*n/(a,b)ax+by=n的解。其他解 x_1,2...x1+(b/(a,b))*t,y_1,2...y1-(a/(a,b))*t (0 <=t<=(a,b)-1)。设d=gcd(a,b) x=x+(a2/d)*t,x的最小非负整数解为 x=(x%(a2/d)+(a2/d))%(a2/d); f=a2/d;x=(x%f+f)%f;新的方程变为a1*(x+(a2/d)*t)+r1=m 我们化简得(a1*a2/d)*t+(a1*x+r1)=m r1=a1*x+r1; a1=lcm(a1,a2)=(a1*a2)/d,m=r1(mod a1)两个线性同余方程合并成一个等效方程,并继续合并下去,最后r1就是方程组的解了,该方法复杂度为O(n*extend_gcd) 我们来看一个应用 http://poj.org/problem?id=3708 f(j) = a[j] (0 f(d*n+j) = d*f(n) + b[j] (0<=j 对于f(N) 把N表示成d进制为N=x[m]*d^m+x[m-1]*d^(m-1)+....+x[1]*d+x[0] 则f(N)= d*(f(x[m]*d^(m-1)))+...d*f(x[1])+b[x[0]] ...... f(N)=d^m*a[x[m]]+d^(m-1)*b[x[m-1]]+....d*b[x[1]]+b[x[0]] 目标是经过若干次f变换,得到M (x[0],x[1],...x[m])是一个群,而b数组的作用就是对任意一个x[i]起到一个置换的作用,把他变成了b[x[i]],从而让其进入到一个循环中  我们可以获得每个x[i]的循环节大小w1[i]以及到达目标的步长w2[i] (关于群,置换,循环节的知识将会在以后的文章中出现)  设经历了p次变换,于是对于任何一个i必有 w1[i]*ki+w2[i]=p (注意a部分只有1个,我们可以单独计算其循环节及步长,最终获得一个类似的方程) 接下来的事情就可以利用上面所说得合并方程组来搞定了,这个问题的关键在于识破d进制的本质,通过置换群的概念 抽化出线性方程组,最终通过合并来解决