数论——中国剩余定理

中国剩余定理(西方数学史中的叫法)

设m1,m2...mk是两两互素的正整数,即: gcd(mi, mj) = 1 (其中 i != j, i, j >= 1且 <=k).
则同余方程组:
x ≡ a1(mod m1)
x ≡ a2(mod m2)
... ...
x ≡ ak(mod mk)
存在唯一[m1,m2...mk]使方程成立.
解法同物不知数是一致的.我们可以稍微模仿一下.
唯一的难题就是如何把上面70, 15, 21的求法,对应到一般情况来.
假设: N1, N2, ... ,Nk.就是对应的权值, 满足如下条件:
N1 能够被 m2, m3..., mk整除,但是除以m1正好余1.
N2 能够被 m1, m3..., mk整除,但是除以m2正好余1.
... ...
Nk能够被m1, m2,...,mk-1整除,但是除以mk正好余1.
N1->Nk如果求出来了,那么假设:
x1 = N1*a1 + N2*a2 + ... + Nk*ak就是我们要求的x一个解, 同物不知数一样,我们把x1 mod (m1*m2*...*mk)的结果
就是x的最小整数解,若为负数,则再加上一个m1*m2*...*mk.因为加减整数倍个m1*m2*...*mk所得结果都是x的解.
所以问题只剩下一个,就是求N1, N2,...,Nk.
怎么求呢?我需要先化简一番:
设m = m1*m2*...*mk, L, J为任意整数.
因为Ni能被m1, m2,...,mi-1, mi+1,...,mk整除(其中i+1<k)
因此: Ni = m/mi *L
又因为Ni除以mi余1
因此: Ni = mi*J + 1
即: mi*J + 1 = m/mi *L ==> (-mi)*J + m/mi*L = 1
而m1-->mk这些数都是互质数,所以(-mi) 同 m/mi也是互质数.即:
gcd(mi, m/mi) = 1也就是说:
 (m/mi)*L + (-mi)*J  = gcd(m/mi, -mi)==>其中-mi和m/mi都是已知的,J和L未知
这就是经典扩展欧几里德定理的原型(由定理知J和L是唯一的, 因此,N1-->Nk有唯一解).
按照扩展欧几里德定理求解即可.
扩展欧几里德定理:
a和b都是不全为0的正整数,则:
a*x + b*y = gcd(a, b)
存在唯一的x, y使得上面等式成立。
(当然,容易得知,如果,a和b中有负数,那么也是成立的。)
本题中,m/mi相当于a, -mi相当于b, L相当于x, J相当于y。求出L, J就能求出Ni。
以上是对中国剩余定理的大体的叙述,至于其中的细枝末节,我想有必要再来详细的解说:因为对于一种定理,从如何发展,如何成熟,如何应用的过程是一个从理论到实践的蜕变,需要从最基础,最暴露的知识理解的层面去深究。
         在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3 余2), 五五数之剩三(除以5 余3),七七数之剩二(除以7 余2),问物几何?” 
        中国剩余定理详细分析 
我们将“孙子问题”拆分成几个简单的小问题,从零开始,试图揣测古人是如何推导出 这个解法的。 


        首先,我们假设n1 是满足除以3 余2 的一个数,比如2,5,8 等等,也就是满足3*k+2 (k>=0)的一个任意数。同样,我们假设 n2 是满足除以 5 余 3 的一个数,n3 是满足除以 7 余2 的一个数。 
有了前面的假设,我们先从n1这个角度出发,已知n1满足除以3余2,能不能使得 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 余2,n2 和n3 必须是3 的倍数。 为使n1+n2+n3 的和满足除以5 余3,n1 和n3 必须是5 的倍数。 
为使n1+n2+n3 的和满足除以7 余2,n1 和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,再将 三个数相加得到解。在求n1,n2,n3 时又用了一个小技巧,以n1 为例,并非从5 和7 的公 倍数中直接找一个除以3 余2 的数,而是先找一个除以3 余1 的数,再乘以2。 


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


最后,我们还要清楚一点,n1+n2+n3 只是问题的一个解,并不是最小的解。如何得到最 
小解?我们只需要从中最大限度的减掉掉3,5,7 的公倍数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 (k 为大于零的整数)。 


此时Ni求解完毕.

我们要求的x的最小整数解也就呼之欲出了.

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>

using namespace std;

//纯数学方法
int calSYDL(itn a[],int m[],int k)//k的值代表方程组的个数
{
    int N[k];
    int mm=1;
    int result;
    for(int i=0;i<k;i++)
    {
        mm*=m[i];
    }
    for(int j=0;j<k;j++)
        
    {
        int L,J;
    exOJLD(mm/m[j],-m[j],L,J);
    N[j]=m[j]*J+1;
    //N[j]=mm/m[j]*L;
    result+=N[j]*a[j];
    }
    return (result%mm+mm)%mm;
    
}

int main()
{
    int a[3]={2,3,2};
    int m[3]={3,5,7};
    cout<<calSYDL(a,m,3)<<endl;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值