扩展中国剩余定理(
e
x
c
r
t
\boldsymbol{excrt}
excrt)是用来解决同余方程组的问题的,我们之前说过中国剩余定理,但是他有一个应用的限制就是
l
c
m
{
p
i
}
=
1
\boldsymbol{lcm\{p_i\}=1}
lcm{pi}=1,但是如果某个恶心的出题人要求这个
l
c
m
{
p
i
}
≠
1
\boldsymbol{lcm\{p_i\}\neq 1}
lcm{pi}=1怎么办呢?你就可以用扩展中国剩余定理吊打他
e x c r t \boldsymbol{excrt} excrt跟普通的 c r t \boldsymbol{crt} crt的思想有一个很大的不同, c r t \boldsymbol{crt} crt使用的是构造法,而 e x c r t \boldsymbol{excrt} excrt是直接暴力
还是对于这样的一个方程
{
x
≡
a
1
m
o
d
p
1
x
≡
a
2
m
o
d
p
2
⋯
x
≡
a
n
m
o
d
p
n
\begin{cases} \boldsymbol{x\equiv a_1\ mod\ p_1} \\ \boldsymbol{x\equiv a_2\ mod\ p_2} \\ \qquad \cdots \\ \boldsymbol{x\equiv a_n\ mod\ p_n} \\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1 mod p1x≡a2 mod p2⋯x≡an mod pn
其中
l
c
m
{
p
i
}
≥
1
\boldsymbol{lcm\{p_i\}\geq 1}
lcm{pi}≥1
我们可以考虑这样一个思路,把问题转化成两个方程的求解,然后把解出来的结果合并成一个新的方程,然后再和下一个求解,以此类推,通过
n
−
1
\boldsymbol{n-1}
n−1次合并,我们就可以得出结果了
引理:
对于两个方程
{
x
≡
a
1
m
o
d
p
1
x
≡
a
2
m
o
d
p
2
⋯
x
≡
a
n
m
o
d
p
n
\begin{cases} \boldsymbol{x\equiv a_1\ mod\ p_1} \\ \boldsymbol{x\equiv a_2\ mod\ p_2} \\ \qquad \cdots \\ \boldsymbol{x\equiv a_n\ mod\ p_n} \\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1 mod p1x≡a2 mod p2⋯x≡an mod pn
如果对于
x
′
\boldsymbol{x^\prime}
x′如果满足前
k
\boldsymbol{k}
k个方程,那么
s
.
t
.
x
=
x
′
+
t
⋅
l
c
m
{
p
j
}
,
x
\boldsymbol{s.t.\ x=x^\prime+t\cdot lcm\{p_j\},x}
s.t. x=x′+t⋅lcm{pj},x为第
k
+
1
\boldsymbol{k+1}
k+1个方程的解,其中
t
∈
Z
+
,
j
∈
[
1
,
k
]
\boldsymbol{t\in Z^+,j\in[1,k]}
t∈Z+,j∈[1,k],证明也是显然的,就是同余的基本定义
有了这个,我们接下来就只需要求出
t
\boldsymbol{t}
t的最小整数解了,设
l
c
m
{
p
j
}
=
M
\boldsymbol{lcm\{p_j\}=M}
lcm{pj}=M,我们的问题就转化成了求
x
′
+
t
M
≡
a
k
+
1
m
o
d
p
k
+
1
\boldsymbol{x^\prime+tM\equiv a_{k+1}\ mod\ p_{k+1}}
x′+tM≡ak+1 mod pk+1
移项,可以得到
t
M
≡
a
k
+
1
−
x
′
m
o
d
p
k
+
1
\boldsymbol{tM\equiv a_{k+1}-x^\prime\ mod\ p_{k+1}}
tM≡ak+1−x′ mod pk+1的
t
\boldsymbol{t}
t的最小整数解,那么也就是求方程
a
x
≡
p
m
o
d
b
\boldsymbol{ax\equiv p\ mod\ b}
ax≡p mod b
的最小整数解
变形,可以得到
a
x
+
b
y
=
p
\boldsymbol{ax+by=p}
ax+by=p
那么我们可以先利用扩展欧几里得求出
a
x
′
+
b
y
′
=
g
c
d
(
a
,
b
)
\boldsymbol{ax^\prime+by^\prime=gcd(a,b)}
ax′+by′=gcd(a,b)的解
那么
x
\boldsymbol{x}
x就等于
x
′
p
g
c
d
(
a
,
b
)
\boldsymbol{\frac{x^\prime p}{gcd(a,b)}}
gcd(a,b)x′p
那么通过这个方法,令
M
=
a
,
a
k
+
1
−
x
′
=
p
,
p
k
+
1
=
b
\boldsymbol{M=a,a_{k+1}-x^\prime=p,p_{k+1}=b}
M=a,ak+1−x′=p,pk+1=b,从而求出
x
\boldsymbol{x}
x即
t
\boldsymbol{t}
t
同时这里我们也可以发现,这组同余方程有解的条件是
g
c
d
(
M
,
p
k
+
1
)
∣
a
k
+
1
−
x
′
\boldsymbol{gcd(M,p_{k+1})|a_{k+1}-x^\prime}
gcd(M,pk+1)∣ak+1−x′,否则无解
然后就是代码了,这里放上的是洛谷模板题的代码,因为模板题保证有解,所以不用判断无解的情况,但是如果题目没有说明应该放上去
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define int long long
int n;
int a[N],b[N],x,y;
int mul(int a,int b,int p){
int res=0;
while(b){
if(b&1)res+=a,res%=p;
a=a+a,a%=p;
b>>=1;
}
return res;
}
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int z=y;
y=x-a/b*y;
x=z;
return d;
}
int excrt(){
int ans=a[1],M=b[1];
Rep(i,2,n){
int GCD=exgcd(M,b[i],x,y);
int val=((a[i]-ans)%b[i]+b[i])%b[i];
x=(x%b[i]+b[i])%b[i];
int t=mul(x,val,b[i])/GCD;
int lM=M;
M=M/GCD*b[i];
ans=ans+mul(lM,t,M);
ans%=M;
}
return ans;
}
signed main()
{
read(n);
Rep(i,1,n)read(b[i]),read(a[i]);
printf("%lld\n",excrt());
return 0;
}

837

被折叠的 条评论
为什么被折叠?



