中国剩余定理和欧几里得定理

                                                中国剩余定理和欧几里得定理                                                

 中国剩余定理

 定理描述:

中国剩余定理:求解同余式组的方法。

例如下面的一元线性同余方程组:

x ≡ a1 (mod m1)

x ≡ a2 (mod m2)

x ≡ a3 (mod m3)

 . . . . . . 

x ≡ an (mod mn)      

中国剩余定理:假设整数m1, m2, m3......, mn两两互质,则对于任意的整数a1, a2, a3...., x有解。

解决问题类型:

  在<孙子算经>里有一个问题: 有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

 

计算及推导

  他的计算过程是:

            70是能被5和7整除的数字,除以3正好余1。

              21是能被3和7整除的数字,除以5正好余1。

            15是能被3和5整除的数字,除以7正好余1。

  最后结果就为:( 70*2 + 21*3 + 15*2 ) % LCM(3, 5, 7) == 23

  就是说对于上面一元组的3个方程要逐级满足,相加之后并不会影响求余的结果,然后modLCM(3, 5,7)就是最小的答案。

  先满足第一个一元组 x ≡ 2 (mod 3) ,70能被5和7整除,除以3余1,然后乘上2后得到N1,N1就满足了一元组中的第一个式子。依次类推,对一元组中的每个式子都求出Ni,然后相加所得的X就是最终答案(因为Ni可以整除集合a中的所有元素,除ai之外,故对于第i个一元组来说,X加上Nj (j!=i), 并不会对mod ai有影响)。

 

  那么再看开始时候提到的一元线性同余方程:(先做几个设定:设Ni为能够被m1, m2,......, mi-1, mi+1, .....mn整除,但是除以mi正好余1)

    X = N1*a1 + N2*a2 + ....... + Nn*an就是我们要求的一个解,解集为X mod LCM(m1, m2, ...., mn)。

 

  剩下的问题就变成了如何求解N1, N2, ......, Nn,我们继续向下看:

    假设m = LCM(m1, m2, ......, mn), x', y'为任意整数。

    因为Ni的性质,Ni可以表示为:Ni == m / mi * x' == mi * y' + 1 ==> m / mi * x' + (-mi) * y' == 1.

  推到现在有没有感觉很熟悉,对的!这个就是扩展欧几里德:对于gcd(a, b) = d, 存在a*x+b*y == gcd(a, b)

      存在gcd(-mi, m/mi) == 1, 对于m / mi * x' + (-mi) * y' == 1, 套用一下扩展欧几里德求出x', 就可以求解出Ni。有了Ni就出X就是分分钟的事情辣!

 

实现代码:

复制代码
 1 LL CRT (LL m[], LL a[], LL n)
 2 {//n 一元同余方程的个数
 3     LL M = 1, ans = 0;
 4     LL Mi, x, y;
 5 
 6     for (int i=0; i)
 7         M *= m[i];
 8 
 9     for (int i=0; i)
10     {
11         Mi = M / m[i];
12         LL d = Extended_Euclid (Mi, m[i], x, y);
13         //扩展欧几里德
14         x = (x % m[i] + m[i]) % m[i];
15         //注意这里x有可能为负数,要转化为正数
16 
17         LL res = quick_add (x, Mi, M);
18         //x * Mi * bi 有可能爆LL,用快速加代替乘法就完美维护
19         res = quick_add (res, a[i], M);
20         ans = (ans + res) % M;
21     }
22     return (ans + M) % M;
23 }
复制代码

欧几里德定理:

  对于整数a, b来说有,gcd (a, b) == gcd (b, a%b) == d,又称为辗转相除法。

 

欧几里德证明:

  先进行设定:x, y, t, k 为整数,并且有d*x == a, d*y == b. t = a - b. k = a / b。

  那么t = d*x - d*k*y; t = d * (x - k * y); 故 t % d == 0;

  所以gcd (b, t) == d == gcd (b, a%b) == gcd (a, b);

  证毕。

 

欧几里德应用:

  用来求a,b的最大公约数。

 

代码实现:

1 int gcd (int a, int b)
2 {
3     return b ? gcd (b, a % b) : a;
4 }

 

扩展欧几里德定理:

  对于不完全为零的非负整数a, b。必定存在整数x, y,满足a*x + b*y == gcd (a, b) == b;

 

扩展欧几里德证明:

  A.  我们知道对于gcd (a, 0) == a, 那么 a*x + b*y == a, 可以解出x = 1, y = 0。

  B. 对于a, b都不等于零的情况来说:

    a*x1 + b*y1 = gcd (a, b);

    b*x2 + (a%b)*y2 = gcd (b, a%b);

    欧几里德告诉我们gcd (a, b) == gcd (b, a%b), 那么我们对上面两个式子进行转化:

    a*x1 + b*y1 == b*x2 + (a%b)*y2;

    b*x2 + (a%b)*y2 == b*x2 + (a - a/b*b)*y2 == b*x2 + a*y2 - a/b*b*y2 == a*y2 + b*(x2 - a/b*y2)

    得出:a*y2 + b*(x2 - a/b*y2) = a*x1 + b*y1,在根据恒等定理可以等到:x1 == y2, y1 == x2 - a/b*y2;

    可以看出,x1, y2是基于x2,y2的。那么我们一次一次向下取余的话,根据基本欧几里德定理可知,总会有一次b == 0的。那么x1, y1 就肯定有解咯!

扩展欧几里德应用:

  1:求解一元线性同余方程,如解决中国剩余定理问题。

  2:求解不定方程,比如说对于:a*x + b*y = c, 如果c % gcd (a, b) == 0, 则对于x, y有解,否则无解。

    那么问题来了,有解的话要怎么求解呢?

    已知扩展欧几里德定理,我们可以求出x0, y0满足:a*x0 + b*y0 == gcd (a, b)

    那么对于a*x1 + b*y1 == c来说,x1 = x0 * c / gcd (a, b), y1 = y0 *c / gcd (a, b);

    对于x, y对应的解集就是:

                    x = x1 + b / gcd (a, b) * t;

                    y = y1 - a / gcd (a, b) * t;(t是任意的自然数)

 

扩展欧几里德实现:

复制代码
 1 LL Extended_Euclid (LL a, LL b, LL &x, LL &y)
 2 {//处理 a * b > 0 的情况
 3     if (b == 0)
 4     {
 5         x = 1;
 6         y = 0;
 7         return a;
 8     }
 9 
10     LL r = Extended_Euclid (b, a%b, x, y), t;
11     t = x;
12     x = y;
13     y = t - a / b * y;
14     return r;
15 }
复制代码

当a, b不同号的话,上面的推论就有一点问题了,在用恒等定理的时候x, y 也应该换号

复制代码
 1 LL Extended_Euclid (LL a, LL b, LL &x, LL &y)
 2 {//可以处理所有的情况
 3     if (b == 0)
 4     {
 5         x = 1;
 6         y = 0;
 7         return a;
 8     }
 9 
10     LL r = Extended_Euclid (b, a%b, x, y), t;
11     t = x;
12     if (a * b < 0)
13     {
14         x = -y;
15         y = a / b * y - t;
16     }
17     else
18     {
19         x = y;
20         y = t - a / b * y;
21     }
22     return r;
23 }
复制代码

你可能感兴趣的:(算法)