起源 在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。
解法:1、找出三个数,从3和5的公倍数中找出取余7等于1的数(即15),从3和7的公倍数中找出取余5等于1的数(即21)从5和7的公倍数中找出取余3等于1的数(即70)。
2、用15乘以2(即x除以7的余数),用21乘以3(即x除以5的余数),用70乘以2(即x除以3的余数),将这三个数加起来,得到30+63+140=233。
3、求3,5,7这三个数的最小公倍数,即105。用233除以105,求出余数为23,23就是符合这个要求的最小解。
解释
首先引入一个公式,即 若a%b=c,则有(a+k*c)%b=c(其中k为整数)。因此设三个数n1,n2,n3,这三个数满足n1%3=2, n2%5=3,n3%7=2。如果要让(n1+n2)%3=2,则需要上面的公式,即n2是3的倍数就成立,同理,要让(n1+n2+n3)%3=2,即让n2,n3都为3的倍数,因此要满足上面的三个公式,就有
1、n1需要是5和7的倍数,n1%3=2。
2、n2需要是3和7的倍数,n2%5=3。
3、n3需要是3和5的倍数,n3%7=2。
要得到最终解,就是(n1+n2+n3),要得到最小解,由第一个公式得即(n1+n2+n3)%105。
代码解决
首先解决求n1,n2,n3的过程,要求n1,应该先在5和7的公倍数中,找到n1%3=1的数,再用这个数乘2,即求5和7的公倍数在取余3时的逆元,在用这个逆元乘2。
求逆元的方法
//拓展欧几里得 ll exgcd(ll a,ll b,ll &x,ll &y) { if(b==0){ x=1; y=0; return a; } ll ret=exgcd(b,a%b,y,x); y-=a/b*x; return ret; } //费马小定理 ll qkpow(ll a,ll p,ll mod) { ll t=1,tt=a%mod; while(p) { if(p&1)t=t*tt%mod; tt=tt*tt%mod; p>>=1; } return t; } ll getInv(ll a,ll mod) { return qkpow(a,mod-2,mod); }
代码实现
ll china(ll a[],ll b[],int n) //a[]为除数,b[]为余数,n为个数 { ll M=1,y,x=0; for(int i=0;i<n;i++){ M*=a[i]; } for(int i=0;i<n;i++){ ll w=M/a[i]; ll tx=0; ll t=exgcd(w,a[i],tx,y); x=(x+w*(b[i]/t)*x)%M; } return (x+M)%M; }