扩展中国剩余定理
算法作用
对于给定的一个同余方程组:
x
≡
c
[
i
]
(
m
o
d
m
[
i
]
)
{ x\equiv c[i] \pmod{m[i]}}
x≡c[i](modm[i])
初始技巧
1、如何使用扩展欧几里得算法求逆元
2、简单数论
解决方法
第一眼:中国剩余定理!
但是,中国剩余定理需要保证m[i]互质,所以这种方法在这里就逊色了
我们可以采用扩展中国剩余定理(excrt)
我们先从最简单的两个式子入手:
x
≡
c
1
(
m
o
d
m
1
)
{ x\equiv c1 \pmod{m1} }
x≡c1(modm1)
x
≡
c
2
(
m
o
d
m
2
)
{x\equiv c2 \pmod{m2} }
x≡c2(modm2)
变形:
x
=
k
1
∗
m
1
+
c
1
{ x=k1*m1+c1 }
x=k1∗m1+c1
x
=
k
2
∗
m
2
+
c
2
{ x=k2*m2+c2 }
x=k2∗m2+c2
联系在一起:
k
1
∗
m
1
+
c
1
=
k
2
∗
m
2
+
c
2
{k1*m1+c1=k2*m2+c2}
k1∗m1+c1=k2∗m2+c2
k
1
∗
m
1
=
(
c
2
−
c
1
)
+
k
2
∗
m
2
{k1*m1=(c2-c1)+k2*m2}
k1∗m1=(c2−c1)+k2∗m2
左右分别除去
p
=
gcd
(
m
1
,
m
2
)
{p=\gcd(m1,m2)}
p=gcd(m1,m2)
原式变为:
k
1
∗
m
1
p
=
c
2
−
c
1
p
+
k
2
∗
m
2
p
{\frac{k1*m1}{p}=\frac{c2-c1}{p}+\frac{k2*m2}{p}}
pk1∗m1=pc2−c1+pk2∗m2
k
1
∗
m
1
p
≡
c
2
−
c
1
p
(
m
o
d
m
2
p
)
{\frac{k1*m1}{p}\equiv \frac{c2-c1}{p} \pmod{\frac{m2}{p}}}
pk1∗m1≡pc2−c1(modpm2)
k
1
≡
c
2
−
c
1
p
∗
(
m
1
p
)
−
1
(
m
o
d
m
2
p
)
{k1\equiv \frac{c2-c1}{p}*(\frac{m1}{p})^{-1} \pmod{\frac{m2}{p}}}
k1≡pc2−c1∗(pm1)−1(modpm2)
k
1
=
c
2
−
c
1
p
∗
(
m
1
p
)
−
1
(
m
o
d
m
2
p
)
+
k
3
∗
m
2
p
{k1= \frac{c2-c1}{p}*(\frac{m1}{p})^{-1} \pmod{\frac{m2}{p}}} +k3*\frac{m2}{p}
k1=pc2−c1∗(pm1)−1(modpm2)+k3∗pm2
我们可以将k1带回原来的x中,得到:
x
=
(
c
2
−
c
1
p
∗
(
m
1
p
)
−
1
(
m
o
d
m
2
p
)
+
k
3
∗
m
2
p
)
∗
m
1
+
c
1
x=(\frac{c2-c1}{p}*(\frac{m1}{p})^{-1} \pmod{\frac{m2}{p}} +k3*\frac{m2}{p})*m1+c1
x=(pc2−c1∗(pm1)−1(modpm2)+k3∗pm2)∗m1+c1
x
=
c
2
−
c
1
p
∗
(
m
1
p
)
−
1
∗
m
1
(
m
o
d
m
2
p
)
+
k
3
∗
m
2
p
∗
m
1
+
c
1
x=\frac{c2-c1}{p}*(\frac{m1}{p})^{-1}*m1 \pmod{\frac{m2}{p}} +k3*\frac{m2}{p}*m1+c1
x=pc2−c1∗(pm1)−1∗m1(modpm2)+k3∗pm2∗m1+c1
x
≡
c
2
−
c
1
p
∗
(
m
1
p
)
−
1
∗
m
1
(
m
o
d
m
2
p
)
+
c
1
(
m
o
d
(
m
2
p
∗
m
1
)
)
x\equiv \frac{c2-c1}{p}*(\frac{m1}{p})^{-1}*m1 \pmod{\frac{m2}{p}} +c1 \pmod{(\frac{m2}{p}*m1)}
x≡pc2−c1∗(pm1)−1∗m1(modpm2)+c1(mod(pm2∗m1))
由于m1,m2,c2,c1都是已知的。
所以这个式子是可求的。
我们再令
m
=
m
2
p
∗
m
1
m=\frac{m2}{p}*m1
m=pm2∗m1
c
=
c
2
−
c
1
p
∗
(
m
1
p
)
−
1
∗
m
1
(
m
o
d
m
2
p
)
+
c
1
c= \frac{c2-c1}{p}*(\frac{m1}{p})^{-1}*m1 \pmod{\frac{m2}{p}} +c1
c=pc2−c1∗(pm1)−1∗m1(modpm2)+c1
于是乎,我们就有了新的同余式:
x
≡
c
(
m
o
d
m
)
x\equiv c \pmod m
x≡c(modm)
再将新求出来的c与m带入原来的c1与m1中,再逐个合并就好了。
全部的c[i]与m[i]合并成一个同余式后,明显,答案就是c mod m了。
代码
#include<cstdio>
#define N 1001
using namespace std;
long long m[N],c[N];
int n;
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if (b==0)
{
x=1;y=0;return a;
}
long long p=exgcd(b,a%b,x,y);
long long t=x;x=y;
y=t-(a/b)*y;return p;
}
long long niyuan(long long x,long long y)
{
long long xx=0,yy=0;
long long p=exgcd(x,y,xx,yy);
while (xx<0) xx+=y;
return xx;
}
int excrt()
{
long long m1=m[1],c1=c[1];
for (int i=2;i<=n;i++)
{
long long m2=m[i],c2=c[i];
long long unless1,unless2;
long long gcdm=exgcd(m1,m2,unless1,unless2);
if ((c2-c1)%gcdm!=0) return -1;
long long newm=m1*m2/gcdm;
long long newc=niyuan(m1/gcdm,m2/gcdm)*((c2-c1)/gcdm)%(m2/gcdm)*m1+c1;
m1=newm;c1=newc;
while (c1<0) c1=(c1+m1)%m1;
}
return c1%m1;
}
int main()
{
freopen("excrt.in","r",stdin);
freopen("excrt.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld%lld\n",&m[i],&c[i]);
long long ans=excrt();
printf("%lld\n",ans);
}