中国剩余定理学习

也是今天上午英语课看的,看大家写的概念很模糊,有些晦涩,直到看到一篇文章《如何为小学生讲透“中国剩余定理”》才完全明白,讲真的有点羞愧,没想到自己已经退步到这个水平了。。。
首先题目要求:

一个整数除以三余一,除以五余二,除以七余三,求这个最小整数

公式:

自拟的“若设要求的这个最小整数为N,数论倒数分别为M1、M2、M3,余数分别为a1、a2、a3,除数的最小公倍数的整数倍为C

N=M1×a1+M2×a2+M3×a3-C  即  70×1+21×2+15×3-105=5
思路:

假设一个整数除以三余一,能被五和七整除,求这个最小整数。大家都知道,能被五和七整除的数是35,但35不满足“除以三余一”条件 ,因为35÷3=11……2,最小的是70,因70÷3=23……1(我们把70这个数称为35相对于3的数论倒数,注意余数是1的时候。),70除以三余一,又能被五和七整除,所以这个最小的整数为70. 即70×1 。

又假如一个整数能被三整除,除以五余二,又能被7整除,求这个最小整数。能被三和七整除的数是21, 21÷5=4……1(这时我们说21相对于5的数论倒数为21),但不是余2,怎办?先看一个例子,6÷5=1……1、12÷5=1……2、18÷5=1……3、24÷5=1……4等,我们发现:被除数扩大几倍,除数不变,余数也扩大几倍。于是便知,因余数为二,所以21需要扩大两倍,即21×2能满足“被三整除,除以五余二,能被7整除”这三个条件,所以这个最小的整数为21×2。

再假如一个整数被三整除,能被五整除,除以七余三,求这个最小整数。能被3和5整除的数为15,而15÷7=2……1(这时我们说15相对于7的数论倒数为21)但不是余3,同理,15×3能满足“被三整除,能被五整除,除以七余三”的条件,所以这个最小的整数为15×3。

列式中70×1+21×2+15×3,为什么把70×1、21×2、15×3它们的积相加呢?也得先看一个例子:11÷7=1……4、(11+7)÷7=2……4、(11+14)÷7=3……4、(11+21)÷7=4……4、(11+28)÷7=5……4等等,我们发现:被除数加上(或减去)除数的倍数,除数不变,余数也不变。为此,70×1满足“除以三余一,能被五和七整除”的条件, 21×2是3的倍数,可得70×1+21×2也满足“除以三余一,能被五和七整除”的条件。反过来说,因70×1是5的倍数,不仅21×2满足“被三整除,除以五余二,能被7整除”的条件,所以加上70×1也满足该条件 ,即(70×1+21×2)满足“被三整除,除以五

余二,能被7整除”条件;同理,既然(70×1+21×2)满足“除以三余一,能被五和七整除”和“被三整除,除以五余二,能被7整除”这两个条件,因15×3既是3的倍数又是5的倍数,由此可得(70×1+21×2+15×3)也能满足“除以三余一,能被五和七整除”和“被三整除,除以五余二,能被7整除”的条件。反过来说,因15×3满足“被三整除,能被五整除,除以七余三”的条件,因(70×1+21×2)又是7的倍数,所以(70×1+21×2+15×3)也能满足“被三整除,除以五余二,能被7整除”条件。综上所述,(70×1+21×2+15×3)同时满足“除以三余一,能被五和七整除”、 “被三整除,除以五余二,能被7整除”和“被三整除,除以五余二,能被7整除”这三个条件,即(70×1+21×2+15×3)满足“除以三余一,除以五余三,除以七余二”的条件,也就是说,这个整数可以是(70×1+21×2+15×3)=157,但它不是最小的,根据“被除数加上(或减去)除数的倍数,除数不变,余数也不变。”所以157可以减去3、5、7的最小公倍数105(有时需要减去最小公倍数的倍数)得52,所以,这个最小的整数为52
然后我也看到了另一种定义,感觉也很棒

中国剩余定理(CRT)的表述如下

设正整数两两互素,则同余方程组

                            

有整数解。并且在模下的解是唯一的,解为

                              

其中,而的逆元

然后是模板:
#include<stdio.h>  
#include <iostream>  
using namespace std;  
//扩展欧几里得算法  
int exgcd(int a,int b,int &x,int &y)  
{  
    int d;  
    if(b==0)  
    {  
        x=1;y=0;  
        return a;  
    }  
    d=exgcd(b,a%b,y,x);  
    y-=a/b*x;  
    return d;  
}  
 //中国剩余定理 ,r[]存放余数 ,prime[]存放两两互质的数  
int Chinese_Remainder(int r[],int prime[],int len)  
{  
    int i,d,x,y,m,n=1,sum=0;  
    //计算所以除数的积n,也是所以除数的最小公倍数  
    for(i=0;i<len;i++)  
        n*=prime[i];  
    //计算符合所以条件的数  
    for(i=0;i<len;i++)  
    {  
        m=n/prime[i];//计算除去本身的所有除数的积m  
        d=exgcd(prime[i],m,x,y);//计算w[i]*x+m*y=gcd(w[i],m)的一个解y  
        //累加整数解y的同并不断对n取余,其利用公式:(a+b)%c=(a%c+b%c)%c  
        sum=(sum+y*m*r[i])%n;  
    }  
    return (n+sum%n)%n;//满足所以方程的最小解  
}  
int main()  
{  
    int n,i;  
    int prime[15],r[15];  
    while (printf("请输入组数n:\n"),scanf("%d",&n)!=EOF)  
    {  
        printf("请依次输入每组的除数和余数:\n");  
        for (i=0;i<n;i++)  
        {  
            scanf("%d%d",&prime[i],&r[i]);  
        }  
        //printf("%d\n",Chinese_Remainder(b,w,n));  
        printf("符合条件的最小整数:%d\n\n",Chinese_Remainder(r,prime,n));  
    }  
    return 0;  
}

模板题:
模板代码:
#include <iostream>  
#include <string.h>  
#include <stdio.h>  
  
using namespace std;  
  
int a[4], m[4];  
  
void extend_Euclid(int a, int b, int &x, int &y)  
{  
    if(b == 0)  
    {  
        x = 1;  
        y = 0;  
        return;  
    }  
    extend_Euclid(b, a % b, x, y);  
    int tmp = x;  
    x = y;  
    y = tmp - (a / b) * y;  
}  
  
int CRT(int a[],int m[],int n)  
{  
    int M = 1;  
    int ans = 0;  
    for(int i=1; i<=n; i++)  
        M *= m[i];  
    for(int i=1; i<=n; i++)  
    {  
        int x, y;  
        int Mi = M / m[i];  
        extend_Euclid(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}  
  
int main()  
{  
    int p, e, i, d, t = 1;  
    while(cin>>p>>e>>i>>d)  
    {  
        if(p == -1 && e == -1 && i == -1 && d == -1)  
            break;  
        a[1] = p;  
        a[2] = e;  
        a[3] = i;  
        m[1] = 23;  
        m[2] = 28;  
        m[3] = 33;  
        int ans = CRT(a, m, 3);  
        if(ans <= d)  
            ans += 21252;  
        cout<<"Case "<<t++<<": the next triple peak occurs in "<<ans - d<<" days."<<endl;  
    }  
    return 0;  
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值