【数学】【数论】中国剩余定理

写在前面

  记录了个人的学习过程,同时方便复习

  • 中国剩余定理

【物不知数】是中国古代著名算题

原载《孙子算经》卷下第二十六题:

“今有物不知其数,三三数之剩二;五五数之剩三;七七数之剩二。问物几何?”

当时虽已有了答案23,但它的系统解法是秦九韶在《数书九章·大衍求一术》中给出的

中国剩余定理是中国古算中最有独创性的成就之一,属现代数论中的一次同余式组问题

——bia度百科

  有x个物件,三个三个数剩2个,五个五个位数剩3个,七个七个数剩2个

  那么就是求解以下同余方程:

    x ≡ 2 (MOD 3)

    x ≡ 3 (MOD 5)

    x ≡ 2 (MOD 7)

  可以用分治的思想来做

  先求得这样的三个数,使得对于每个模数而言,仅有模它得到的余数为1

(注意,这样的解法仅在模数两两互质的情况下成立)

    x1 ≡ 1 (MOD 3)  x2 ≡ 0 (MOD 3)  x3 ≡ 0 (MOD 3)

    x1 ≡ 0 (MOD 5)  x2 ≡ 1 (MOD 5)  x3 ≡ 0 (MOD 5)

    x1 ≡ 0 (MOD 7)  x2 ≡ 0 (MOD 7)  x3 ≡ 1 (MOD 7)

    就第一组x1的同余方程来说,它的解是5*7*n1

    n1*35 ≡ 1 (MOD 3)

    也就是 n1*2 ≡ 1 (MOD 3)

    n1 == 2,x1 == 70

    同理得到n2 == 1,x2 == 21,n3 == 1,x3 == 15

  因为要求的余数为2,3,2,分别将x1,x2,x3乘上对应的余数

  再把得到的x1*2,x2*3,x3*2加起来就好了,这样的得到的就是一种解

  希望求最小正整数解,把得到的数模上3,5,7的最小公倍数就好了

 

  推广到其他的情形,需要解这样的一组同余方程

    x ≡ k1 (MOD p1)

    x ≡ k2 (MOD p2)

    ......

    x ≡ kn (MOD pn)

    (其中p1,p2,......,pn之间两两互质)

  求出它们的最大公因数M == ki=1pi (因为这些数两两互质)

  则对于每一个数p,p与M/p的最大公因数为1

  使用拓展欧几里得算法求出一组x,y,使得M/p*x + p*y ≡ 1 (MOD M)

  留下来x就好,y不用管了

x == (x1*p1*k1 + x2*p2*k2 + ...... + xn*pn*kn) MOD M

  这样就算好啦

  代码如下:

C++:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int const MAXN=10010;
 6 int x,y;
 7 int k;//k组同余方程
 8 int a[MAXN];//每个同余方程的余数
 9 int b[MAXN];//每个同余方程的模数
10 int ans;
11 int lcm=1;
12 
13 void exgcd(int a,int b)
14 {
15     if(b==0){x=1;y=0;}
16     else{
17         exgcd(b,a%b);
18         int tmp=x;
19         x=y;y=tmp-a/b*y;
20     }
21     return;
22 }
23 
24 int main(int argc,char *argv[],char *enc[])
25 {
26     scanf("%d",&k);
27     for(int i=1;i<=k;++i)
28         scanf("%d%d",&b[i],&a[i]);
29         
30     for(int i=1;i<=k;++i)
31         lcm*=b[i];
32     for(int i=1;i<=k;++i)
33     {
34         exgcd(lcm/b[i],b[i]);
35         x=(x%b[i]+b[i])%b[i];
36         
37         ans=(ans+(lcm/b[i])*x*a[i])%lcm;
38     }
39     
40     printf("%d",ans);
41     return 0;
42 }

Java:

 1 import java.io.*;
 2 import java.util.*;
 3 
 4 class pony{
 5 
 6     static int MAXN=10010;
 7     static int x,y;
 8     static int k;//k组同余方程
 9     static int[] a=new int[MAXN];//每个同余方程的余数
10     static int[] b=new int[MAXN];//每个同余方程的模数
11     static int ans;
12     static int lcm=1;
13 
14     static void exgcd(int a,int b)
15     {
16         if(b==0){x=1;y=0;}
17         else{
18             exgcd(b,a%b);
19             int tmp=x;
20             x=y;y=tmp-a/b*y;
21         }
22         return;
23     }
24 
25     public static void main(String[] args) throws Exception {
26         
27         Scanner cin=new Scanner(System.in);
28         
29         k=cin.nextInt();
30         for(int i=1;i<=k;++i)
31         {
32             b[i]=cin.nextInt();
33             a[i]=cin.nextInt();
34         }
35 
36         for(int i=1;i<=k;++i)
37             lcm*=b[i];
38         for(int i=1;i<=k;++i)
39         {
40             exgcd(lcm/b[i],b[i]);
41             x=(x%b[i]+b[i])%b[i];
42 
43             ans=(ans+(lcm/b[i])*x*a[i])%lcm;
44         }
45 
46         System.out.println(ans);
47     }
48 }

因为两两互质,最小公倍数就是这些数的积,我在对唯一分解定理的研究中提到过

  • 拓展中国剩余定理

  以上方法仅仅适用于每个模数两两互质的情况

  但是最常见的情况还是所有模数不满足两两互质

  这样的话,中国剩余定理就不再适用

  需要使用[◹]拓展中国剩余定理

猜你喜欢

转载自www.cnblogs.com/Antigonae/p/10129122.html