1.中国剩余定理(小故事开头)
在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3 余2),五五数之剩三(除以5 余3),七七数之剩二(除以7 余2),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。
对于这个问题,我们一般会想出很多种解法,但像我这样懒勤劳的人,我还是喜欢直接看最后的结论。
2.理论推导(看结论会用就好)。
对于这个逆元实际上就是我们用exgcd也就是扩展欧几里得算法求出的x的值。
及最后结果应该为
ans=(ans+Mi*a[i]*x)%M
三.实战
题目描述
现有两组数字,每组 k 个。
第一组中的数字分别用 a1,a2,⋯,ak 表示,第二组中的数字分别用 b1,b2,⋯,bk 表示。
其中第二组中的数字是两两互素的。求最小的 n∈N,满足对于 ∀i∈[1,k],有 bi∣(n−ai)。
输入描述
第一行一个整数 k。
第二行 k 个整数,表示:a1,a2,⋯,ak。
第三行 k 个整数,表示:b1,b2,⋯,bk。
输出描述
输出一行一个整数,为所求的答案 n。
样例输入 1
3 1 2 3 2 3 5
样例输出 1
23
#include<bits/stdc++.h>
using namespace std;
long long m[20];
long long a[20];
//扩展欧几里得定理
void exgcd(long long a,long long b,long long &x,long long &y){
if(b==0){
x=1;
y=0;
return ;
}
else{
exgcd(b,a%b,x,y);
long long temp=x;
x=y;
y=temp-a/b*y;
return ;
}
}
//中国剩余定理
long long crt(int n){
long long x,y,M=1;
long long ans=0;
for(int i=1;i<=n;i++){
M*=m[i];
}
for(int i=1;i<=n;i++){
long long Mi=M/m[i];
exgcd(Mi,m[i],x,y);
ans=(ans+Mi*a[i]%M*x%M)%M;//取余M防止过大
}
return (ans+M)%M;//这是为了确保为非负整数
}
int main(){
int k;
cin>>k;
for(int i=1;i<=k;i++){
cin>>a[i];
}
for(int i=1;i<=k;i++){
cin>>m[i];
}
for(int i=1;i<=k;i++){
a[i]=(a[i]+m[i])%m[i];
}//防止非正整数的出现
long long res=crt(k);
cout<<res<<endl;
system("pause");
return 0;
}
至此,功德圆满。
注:轻轻关注一下这位正在掉头发的帅气的博主!