中国剩余定理
求下列同余方程组的解(保证 n i , n j n_i,n_j ni,nj两两互质):
x
≡
a
1
(
m
o
d
n
1
)
x≡a_1(\mod n_1)
x≡a1(modn1)
x
≡
a
2
(
m
o
d
n
2
)
x≡a_2(\mod n_2)
x≡a2(modn2)
x
≡
a
3
(
m
o
d
n
3
)
x≡a_3(\mod n_3)
x≡a3(modn3)
…
x
≡
a
k
(
m
o
d
n
k
)
x≡a_k(\mod n_k)
x≡ak(modnk)
唯一解: a n s ≡ ∑ a i ∗ c i ( m o d M ) ans≡\sum a_i*c_i(\mod M) ans≡∑ai∗ci(modM),其中 M = ∏ n i , m i = M / n i , m i − 1 M=\prod n_i,m_i=M/n_i,m_i^{-1} M=∏ni,mi=M/ni,mi−1为 m i m_i mi在 n i n_i ni意义下的逆元, c i = m i ∗ m i − 1 c_i=m_i*m_i^{-1} ci=mi∗mi−1(不对n_i取模)。
证明:
- i ≠ j i≠j i=j时,因为 m i = M / n i m_i=M/n_i mi=M/ni,所以 m i m o d n j = 0 m_i \mod n_j=0 mimodnj=0,即 c i ≡ m i ≡ 0 ( m o d n j ) c_i≡m_i≡0(\mod n_j) ci≡mi≡0(modnj)
- a n s ≡ ∑ j = 1 k a j ∗ c j ( m o d n i ) ans≡\sum_{j=1}^k a_j*c_j(\mod n_i) ans≡∑j=1kaj∗cj(modni)
- a n s ≡ a i ∗ c i ( m o d n i ) ans≡a_i*c_i(\mod n_i) ans≡ai∗ci(modni)
- 因为 c i = m i ∗ m i − 1 c_i=m_i*m_i^{-1} ci=mi∗mi−1,所以 c i ≡ 1 ( m o d n i ) c_i≡1(\mod n_i) ci≡1(modni)
- a n s ≡ a i ( m o d n i ) ans≡a_i(\mod n_i) ans≡ai(modni)
代码:
int a[N],b[N],m[N],c[N];
void exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x = 1;
y = 0;
return ;
}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
int crt(int n)
{
int mul = 1,res = 0;
for(int i=1;i<=n;i++)
mul *= a[i];
for(int i=1;i<=n;i++)
m[i] = mul/a[i];
for(int i=1;i<=n;i++)
{
int x,y;
exgcd(m[i],a[i],x,y);
c[i] = m[i]*x;
res = (res + b[i]*c[i])%mul;
}
return (res+mul)%mul;
}
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
cout<<crt(n)<<endl;
return 0;
}
拓展中国剩余定理:
求下列同余方程组的解(不保证 n i , n j n_i,n_j ni,nj两两互质):
x
≡
a
1
(
m
o
d
n
1
)
x≡a_1(\mod n_1)
x≡a1(modn1)
x
≡
a
2
(
m
o
d
n
2
)
x≡a_2(\mod n_2)
x≡a2(modn2)
x
≡
a
3
(
m
o
d
n
3
)
x≡a_3(\mod n_3)
x≡a3(modn3)
…
x
≡
a
k
(
m
o
d
n
k
)
x≡a_k(\mod n_k)
x≡ak(modnk)
先看前两个方程:
- x = k 1 ∗ n 1 + a 1 = k 2 ∗ n 2 + a 2 x=k_1*n_1+a_1=k_2*n_2+a_2 x=k1∗n1+a1=k2∗n2+a2
- a 2 − a 1 = k 1 ∗ n 1 − k 2 ∗ n 2 a_2-a_1=k_1*n_1-k_2*n_2 a2−a1=k1∗n1−k2∗n2
- 当 ( a 2 − a 1 ) m o d g c d ( n 1 , n 2 ) ≠ 0 (a_2-a_1) \mod gcd(n_1,n_2)≠0 (a2−a1)modgcd(n1,n2)=0时无解
- 有解时,通过exgcd算法求出 k 1 , k 2 k_1,k_2 k1,k2的一组解
- 回代 k 1 k_1 k1,即有 x ≡ k 1 ∗ n 1 + a 1 ( m o d l c m ( n 1 , n 2 ) ) x≡k_1*n_1+a_1(\mod lcm(n_1,n_2)) x≡k1∗n1+a1(modlcm(n1,n2))
- 多次求解,合并
代码:
int a[N],b[N];
void exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x = 1;
y = 0;
return ;
}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
int qmul(ll a,ll b,ll p)
{
ll res = 0;
while(b)
{
if(b&1)
res = (res + a) % p;
a = (a+a)%p;
b>>=1;
}
return res;
}
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
int ans = b[1],M = a[1];
for(int i=2;i<=n;i++)
{
int x,y;
int c = ((b[i]-ans)%a[i]+a[i])%a[i];
exgcd(M,a[i],x,y);
int d = __gcd(M,a[i]);
x = qmul(x,c/d,a[i]);
ans+=M*x;
M*=a[i]/d;
ans = (ans+M)%M;
}
cout<<ans<<endl;
return 0;
}