中国剩余定理(孙子定理)
前置知识:逆元,取模运算。
先说说这个定理可以干什么吧。
例题:设一个非负整数X,X%3的值为2,X%5的值为3,X%7的值为6。那么X的值是多少??
即
%3
%5
%7
计算:
1.先求出3,5,7的公倍数M,M也就是105.
2.对于第一个式子,设=M/3,
也就是35.(别问为什么这么蠢的在这里绕,耐心看),再求
在模3下的逆元
。
(逆元就是在模一个数情况下,乘积为1的的数,比如:在对5取模的情况下,2即为3的逆元,2*3等于6,再对5取余,就是1了
是不是很像普通情况下的倒数)。
那么现在*
再对3取模的值就是1了,那么2*
*
对3取模就是2。再看,现在2*
*
是不是就是第一式子的解了。那么对于其他的
式子来说呢?这个值对其他式子的模数计算,发现会等于0,因为最开始的时候计算M就是那些模数乘出来的啊,而是除去了当前式子的模数,这时候
还是其他式子 模数的倍数。
3.我们对每一个式子都进行上述的运算,每次都会得到一个 ,
就是每个式子取模剩下的数,比如第一个式子就是2。
就是公倍数(所有式子的模数)M除以当前式子的模数的值。
则是逆元。然后把所有的
加起来得到sum,sum就是一个我们
想要的值,怎么稀里糊涂就算完了??看上面的红字,每一次算出来的 对于其它式子来说,在对其它的式子的模数取模之后,就变成0了。所以sum即是所有式子的解,由于要求最小的非负整数解,所以sum再对M取模。
注意:中国剩余定理的使用前提是每个式子中的所有模数都需要互质,比如上面式子中的3,5,7就是互质的。
想知道为什么??下一篇扩展中国剩余定理再说了。
最后,代码:
#include<bits/stdc++.h>
using namespace std;
int n;
long long int arr[20];
long long int m[20];
long long int mod;
long long int quick_multiple(long long int n,long long int base)
{
if(n<0)
{
base*=-1;
n*=-1;
}
long long int ans=0;
while(n)
{
if(n&1)
{
ans+=base;
ans%=mod;
}
n>>=1;
base+=base;
base%=mod;
}
return ans;
}
void exgcd(long long int a,long long int b,long long int &x,long long int &y)
{
if(!b)
{
x=1;
y=0;
return ;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
long long int CRT()
{
long long int M=1;
long long int ans=0;
long long int x,y,t;
for(int i=0;i<n;++i)
M*=m[i];
mod=M;
for(int i=0;i<n;++i)
{
t=M/m[i];
exgcd(t,m[i],x,y);
ans=(ans+quick_multiple(quick_multiple(arr[i],x),t))%M;
}
return (ans+M)%M;
}
int main()
{
cin>>n;
for(int i=0;i<n;++i)
cin>>arr[i];
for(int i=0;i<n;++i)
cin>>m[i];
cout<<CRT()<<endl;
return 0;
}