在学习了exgcd之后再来学一个中国剩余
问题:一个数除若干个数( w【】)(互质的), 余数分别是若干个数(a【】),求这个数(最小)多少
嘛 先直接看代码
#include <iostream>
using namespace std;
int exgcd(int a, int b, int& x, int& y)
{
int t,gcd;
if (b == 0)
{
x = 1;y = 0;return a;
}
gcd=exgcd(b, a%b, x, y);
t = x;
x = y;
y = t - a/b*y;
return gcd;
}
int Chinese_Remainder(int a[],int w[],int len) //中国剩余定理 a[]存放余数 w[]存放两两互质的数
{
int i,d,x,y,m,n,ret;
ret=0;
n=1;
for (i=0;i<len;i++)
n*=w[i];
for (i=0;i<len;i++)
{
m=n/w[i];
d=exgcd(w[i],m,x,y);
ret=(ret+y*m*a[i])%n;
}
return (n+ret%n)%n;
}
int main()
{
int n,i;
int w[100],b[100];
while (scanf("%d",&n),n)
{
for (i=0;i<n;i++)
{
scanf("%d%d",&w[i],&b[i]);
}
printf("%d/n",Chinese_Remainder(b,w,n));
}
return 0;
}
概括过程算法的过程:
1 计算出n个数。 其中每个数是(比如第n个)是w数组中的除了第n个位置以外的所有数的乘积的倍数的其中的除以w【n】能够等于a【n】的最小的数。(这句话的定语确实有点太长了,具体原理请配合其他文章食用吧)
把这n和数加一起,除以w数组所有数的乘积的余数是答案。
代码中最关键的三行
m=n/w[i];
d=exgcd(w[i],m,x,y);
ret=(ret+y*m*a[i])%n;
使用exgcd 计算出来的一个y ,在此时 m*y mod w[i]=1。
要想让余数变成a[i],就在前面的式子左半部分再乘一个a[i],所以上行代码中第3行有3个乘数 m y a[i]