中国剩余定理(CRT,孙子定理)

首先自豪一波

然后%%%%%一波julao孙子算经

然后开始正题2333逃

问题引入:有一群猪,三只三只的分,剩两只,五只五只的分,剩三只,七只七只的分,剩两只,求一共几只猪?

暴力求解:我们设一共有n只猪,那么n%3=2,n%5=3,n%7=2,因为n%3=n%7,所以n%(3*7)=2,所以n的个位可以为3/4/5/6/7/8/9/0,因为n%5=3,所以n的个位必定为3或8,所以结果可以是23或128,这当然不算是正解,正解是CRT,我们先引入中国剩余定理(正解自己百度一下??)

定理内容:设集合mi是一组两两互质的数的集合,N=m1*m2*...*mi,Mi=N/mi,ti是Mi在 mod mi意义下的逆元,即Mi*ti≡1 (mod mi),对于任意n个整数a1~an,方程组  {x≡ai (mod mi)}有整数解,解为x=Σ(a1M1t1~anMntn)    (mod N)

定理证明:因为Mi=N/mi,所以Mi是集合中除mi以外所有数的倍数,所以对于任意k,k!=i,ai*Mi*ti ≡ 0 (mod mk),且ai*Mi*ti ≡ ai (mod mi),所以将上述x带入方程组的任意项,发现除ai这项外,其他x中含有的项mod mi=0,所以mod mi后,只剩ai*Mi*ti,该项与ai同余,故x存在

(所以说,将3,5,7看做一个集合mi,求解x即为猪的头数)

注:上述定理条件为集合中的元素两两互质,如有证明错误请联系博主

附一下求猪的只数的CRT代码

//By AcerMo
#include
#include
#include
#include
#include
using namespace std;
int n,m[105],a[105],lcm=1;
int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
	{
		x=1,y=0;
		return a;
	}
    int d=exgcd(b,a%b,x,y),tmp=x;
    x=y,y=tmp-(a/b)*y;
    return d;
}//exgcd求逆元 
int CRT()
{
    int i,x,y,re=0;
    for(int i=1;i<=n;i++) 
		lcm=lcm*m[i];//初始的最小公倍数是自己 
    for(int i=1;i<=n;i++)
	{
        int kl=lcm/m[i];
        exgcd(kl,m[i],x,y);//求逆元 
        x=(x%m[i]+m[i])%m[i];//当前数的逆元 
        re=(re+a[i]*x*kl)%lcm;//套公式 
    }
    return re;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
		scanf("%d %d",&m[i],&a[i]);;
    printf("%d",CRT());
    return 0;
}

你可能感兴趣的:(数论&&组合数学)