一个整数除以三余一,除以五余二,除以七余三,求这个最小整数
自拟的“若设要求的这个最小整数为N,数论倒数分别为M1、M2、M3,余数分别为a1、a2、a3,除数的最小公倍数的整数倍为C
假设一个整数除以三余一,能被五和七整除,求这个最小整数。大家都知道,能被五和七整除的数是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)满足“被三整除,除以五
中国剩余定理(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;
}