1.朴素欧几里得:辗转相除法求gcd(a,b)(a和b的最大公约数),gcd(a,b)=gcd(b,a%b)

gcd(a,b) = gcd(b,amod b) (不妨设a>b 且r=a mod b ,r不为0)

 

证法一

a可以表示成a = kb + r(a,b,k,r皆为正整数),则r = a modb

假设d是a,b的一个公约数,记作d|a,d|b,即a和b都可以被d整除。

而r= a - kb,两边同时除以d,r/d=a/d-kb/d=m,等式左边可知m为整数,因此d|r

因此d也是(b,a mod b)的公约数

因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。

 

2.拓展欧几里得:必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。

首先证明这个命题成立

设a>b

(1)b=0时,gcd(a,b)=a,x=1,y=0

(2)ab≠0 gcd(a,b)=ax+by

同理存在gcd(b,a%b)=bx1+(a%b)y1

gcd(a,b)=gcd(b,a%b)

∴ax+by=bx1+(a%b)y1

ax+by=bx1+(a-(a/b)*b)y1  这一步特殊而重要,这里的“/”指的是计算机中的除并向下取整

ax+by=ay1+b(x1-(a/b)y1)

因为这个等式恒成立,所以x=y1,y=x1-(a/b)y1,

又因为当b=0时,x=1,y=0,这样就可以确保递推能求解x,y了,得证

上述程序只是得到了一组解,很显然解是不唯一的:x增加b, y减少a一定是原方程的一组解:

a *  (x + b)  + b * (y - a) =a * x + b * y = (a, b)

然而在应用上,往往并不是如此简单,很多时候会求解不定方程a * x + b * y =n。这个时候还是应用上面的算法:

(1)(ab), c = (ab),如果! c|n,则不存在整数解。因为将上式左右两边都除以c,可以知道,左边为整数,右边为非整数,故矛盾。

(2)将左右两边同时除以c,设得到新的方程为a' * x + b' * y = n',应用上述算法求a' * x + b' * y = 1的解(由第一步知道(a'b') = 1)。设结果为x', y'

(3)x = x' * n' , y = y' * n'是方程a * x + b * y =n。这个比较好理解,将a' * x + b' * y= 1两边同时扩大n'倍就行了。

(4)x = x' * n' + t * b, y = y' * n' - t * at为整数)是原方程a * x + b * y =n的所有解。

 

应用:

1.用扩展gcd解线性方程ax+by=c

问题:ax+by=c,已知abc,求解使该等式成立的一组xy。其中abcxy均为整数

a,b的最大公约数为gcd(a,b)。如果c不是gcd(a,b)的倍数,则该等式无解,因为等式左边除以gcd(a,b)是整数,而等式右边除以gcd(a,b)后为小数。

因此,只有当cgcd(a,b)的倍数的时候,该等式有解。这样,可以通过计算使ax1+by1=gcd(a,b)成立的x1y1,然后有x=(c/gcd(a,b))*x1y=(c/gcd(a,b))*y1,得到x,y

问题就被转换为求使ax+by=gcd(a,b)成立的一组x,y。这可以用扩展欧几里德算法求解。如下:

如果b为零,则gcd(a,b)=a,那么x=1,y=0为一组解。

如果b不为零,根据欧几里德定理,可以设

ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2=bx2+(a-(a/b)*b)y2

化简后有x1=y2y1=x2-(a/b)y2。因此x1,y1依赖于x2,y2,同理依次类推递归调用求出x3,y3,x4,y4……,类似于辗转相除,直到b=0时,求出xn,yn,便可以推出x1,y1的值。

 

 

 

2.扩展gcd解同余方程(把同余方程转为线性方程)

NOIP2012d2t1 同余方程  ax ≡ 1 (mod b)  最小的整数解x。

满足a*x≡1 (mod p)x

对于正整数 和 ,如果有 ,那么把这个同余方程中 的最小正整数解叫做 模 的逆元。

 

逆元求法

 扩展欧几里得&中国剩余定理(学习资料)

 

3.方程组的情形(中国剩余定理)

中国剩余定理介绍
在《孙子算经》中有这样一个问题:今有物不知其数,三三数之剩二(除以3 2),
五五数之剩三(除以5 3),七七数之剩二(除以7 2),问物几何?这个问题称为
子问题,该问题的一般解法国际上称为中国剩余定理。具体解法分三步:

找出三个数:从3 5 的公倍数中找出被7 除余1 的最小数15,从3 7 的公倍数中找出被 5 除余1 的最小数21,最后从5 7 的公倍数中找出除3 1 的最小数70
15 乘以22 为最终结果除以7 的余数),用21 乘以33 为最终结果除以5 的余数),同理,用70 乘以22 为最终结果除以3 的余数),然后把三个乘积相加(15*2+21*3+70*2)得到和233 233 除以 357 三个数的最小公倍数 105,得到余数 23,即 233%105=23。这个余数 23 就是符合条件的最小数。就这么简单。我们在感叹神奇的同时不禁想知道古人是如何想到这个方法的,有什么基本的数学依据吗?

中国剩余定理分析
我们将孙子问题拆分成几个简单的小问题,从零开始,试图揣测古人是如何推导出
这个解法的。

首先,我们假设n1 是满足除以3 2 的一个数,比如258 等等,也就是满足3*k+2
k>=0)的一个任意数。同样,我们假设 n2 是满足除以 5 3 的一个数,n3 是满足除以 7 2 的一个数。

有了前面的假设,我们先从n1这个角度出发,已知n1满足除以32,能不能使得 n1+n2 的和仍然满足除以3 2?进而使得n1+n2+n3 的和仍然满足除以3 2

这就牵涉到一个最基本数学定理,如果有a%b=c,则有(a+kb)%b=c(k 为非零整数),换句话说,如果一个除法运算的余数为 c,那么被除数与 k 倍的除数相加(或相减)的和(差)再与除数相除,余数不变。这个是很好证明的。

以此定理为依据,如果n2 3 的倍数,n1+n2 就依然满足除以3 2。同理,如果n3
也是3 的倍数,那么n1+n2+n3 的和就满足除以3 2。这是从n1 的角度考虑的,再从n2 n3 的角度出发,我们可推导出以下三点:

为使n1+n2+n3 的和满足除以3 2n2 n3 必须是3 的倍数。
为使n1+n2+n3 的和满足除以5 3n1 n3 必须是5 的倍数。
为使n1+n2+n3 的和满足除以7 2n1 n2 必须是7 的倍数。
因此,为使n1+n2+n3 的和作为孙子问题的一个最终解,需满足:

n1 除以3 2,且是5 7 的公倍数。
n2
除以5 3,且是3 7 的公倍数。
n3
除以7 2,且是3 5 的公倍数。
所以,孙子问题解法的本质是从5 7 的公倍数中找一个除以3 2 的数n1,从3 7
的公倍数中找一个除以5 3 的数n2,从3 5 的公倍数中找一个除以7 2 的数n3,再将三个数相加得到解。在求n1n2n3 时又用了一个小技巧,以n1 为例,并非从5 7 的公倍数中直接找一个除以3 2 的数,而是先找一个除以3 1 的数,再乘以2

这里又有一个数学公式,如果a%b=c,那么(a*k%b=a%b+a%b+„+a%b%b=(c+c+„+c)%b=kc%bk>0,
也就是说,如果一个除法的余数为c,那么被除数的k 倍与除数相除的余数为kc。展开式中已证明。

最后,我们还要清楚一点,n1+n2+n3 只是问题的一个解,并不是最小的解。如何得到最
小解?我们只需要从中最大限度的减掉掉357 的公倍数105 即可。道理就是前面讲过的定理如果a%b=c,则有(a-kb)%b=c”。所以(n1+n2+n3%105 就是最终的最小解。
总结经过分析发现,中国剩余定理的孙子解法并没有什么高深的技巧,就是以下两个基本数学定理的灵活运用:
如果 a%b=c , 则有 (a+kb)%b=c (k 为非零整数)
如果 a%b=c,那么 (a*k)%b=kc%b (k为大于零的整数)

推广到一般情况:

例如下面的一元线性同余方程组:
x ≡ a1 (mod m1)
x ≡ a2 (mod m2)
x ≡ a3 (mod m3)
… …
x ≡ an (mod mn)
假设整数m1, m2, m3……, mn两两互质,m=m1*…*mn,则对于任意的整数a1, a2, a3….an, X有解。
求解X过程:X=(除以m1a1a2,a3…an的公倍数+…+除以mjajm1…mj-1, mj+1…mn的公倍数+除以mnanm1,…, mn-1的公倍数)%LCM(m1,…, mn)=[(除以m1a1a2,a3…an的公倍数)%LCM(a1,…,an)+…+(除以mjajm1…mj-1, mj+1…mn的公倍数)%LCM(m1,…, mn)+(除以mnanm1,…, mn-1的公倍数) %LCM(m1,…,mn)]%LCM(m1,…, mn)
问题转换为:找到除以mjajm1…mj-1, mj+1…mn的公倍数。这里有个技巧,先找到除以mj1m1…mj-1, mj+1…mn的公倍数Nj,然后Nj*aj即可。
问题转换为:求Njm1…mj-1, mj+1…mn的最小公倍数Mj=m/mj,因为余数m1…mn互为质数,所以Mj是最小公倍数)。
问题转换为:求Mj的某个倍数Nj=Mj*R,使得除以mj1
问题转换为:求R,使得Mj*R≡1(mod mj),即求Mj的乘法逆元。
求乘法逆元(用扩展欧几里得算法):Mj*R+mj*y=1,变量是Ry,调用函数exGcd(Mj,mj,R,y)即可。
最终X=西格玛(Rj*Mj)*a[j]%m
代码,变量名和分析过程使用的一致:

long longexGcd(long long a,long long b,long long &x,long long &y){

    if(0==b) {

        x=1;y=0;return a;

    }

    long long gcd=exGcd(b,a%b,y,x);

    y-=a/b*x;  return gcd;

}

long long lmes(){

    long long X=1,R,y,X,Mi;

    for(int i=0;i<n;i++) m*=a[i];//n[i]是第i个余数

    for(int i=0;i<n;i++) {

        Mi=m/n[i];

        exGcd(Mi,a[i],R,y);

        X+=(a[i]*Mi*R)%m;

    }

    return (X+m)%m;//X可能是负数

}

 

m1,…,mn不互质的情形:合并方程。

扩展欧几里得&amp;中国剩余定理(学习资料)

 扩展欧几里得&amp;中国剩余定理(学习资料)

long long Rem(longlong a[],long longm[],int num){

    long longn1=n[0],a1=a[0],n2,a2,k1,k2,x0,gcd,c;

    for(int i=1;i<num;i++){

        n2=n[i],a2=a[i];

        c=a2-a1;

        gcd=exGcd(n1,n2,k1,k2);//解得:n1*k1+n2*k2=gcd(n1,n2)

        if(c%gcd){

            flag=1;

            return 0;//无解

        }

       x0=c/gcd*k1;//n1*x0+n2*(c/gcd*k2)=c PS:k1/gcd*c错误!

        t=n2/gcd;

        x0=(x0%t+t)%t;//求n1*x0+n2*y=c的x0的最小解

        a1+=n1*x0;

        n1=n2/gcd*n1;

    }

    return a1;

}

21:50:03
游来游去 2017/5/14 21:50:03

扩展欧几里得&amp;中国剩余定理(学习资料)

{这一步通过exgcd求得逆元k1

游来游去 2017/5/14 21:51:05

用x0存k1

游来游去 2017/5/14 21:51:39

扩展欧几里得&amp;中国剩余定理(学习资料)
k1=K ( mod n2/d)

游来游去 2017/5/14 21:51:58

K=k1 mod (n2/d)
21:52:12
游来游去 2017/5/14 21:52:12

下面的程序就是这样实现的。}


HDU 2669Romantic

http://acm.nyist.net/JudgeOnline/problem.php?pid=144小珂的苦恼

POJ 1061 青蛙的约会

HDU1576 A/B

HDU 5512

pku2115

pku2891

pku1061

HDU 1370

HDU5768 Lucky7 数论

HDU 1573 X问题

pku2142

POJ 2348Euclid's Game

HDU 4675 GCD ofSequence 2013多校7 1010数学题)

HDU 4655 CutPieces2013多校6 1001简单数学题)

 


相关文章:

  • 2021-10-18
  • 2022-12-23
  • 2021-07-05
  • 2021-08-22
  • 2021-05-25
  • 2022-01-22
猜你喜欢
  • 2021-06-08
  • 2021-12-14
  • 2022-12-23
  • 2022-12-23
  • 2021-07-06
  • 2021-10-24
  • 2021-12-18
相关资源
相似解决方案