文章目录
前置知识
快速乘
扩展欧几里得定理
同余方程
目的
求最小的正整数 x x x,使其满足
{ x ≡ a 1 ( m o d m ) x ≡ a 2 ( m o d m 2 ) ⋮ x ≡ a n ( m o d m n ) \begin{cases} x\equiv a_{1}\left( mod\ m\right) \\ x\equiv a_{2}\left( mod\ m_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( mod\ m_{n}\right) \end{cases} ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x≡a1(mod m)x≡a2(mod m2)⋮x≡an(mod mn)
其中 m 1 , m 2 … m n m_1,m_2\dots m_n m1,m2…mn互质
求法
令
M
=
∏
i
=
1
n
m
i
\begin{aligned}M=\prod ^{n}_{i=1}m_{i}\end{aligned}
M=i=1∏nmi
设
ω
i
=
M
m
i
\omega _{i}=\dfrac {M}{m_{i}}
ωi=miM
ω i − 1 \omega_i^{-1} ωi−1为 ω i \omega_i ωi在 m o d m i mod\ m_i mod mi下的逆元
则有
x
=
∑
i
=
1
n
a
i
ω
i
ω
i
−
1
m
o
d
M
\begin{aligned}x=\sum ^{n}_{i=1}a_{i}\omega_{i}\omega_{i}^{-1} mod\ M\end{aligned}
x=i=1∑naiωiωi−1mod M
当对 m i m_i mi取模时,除了有 ω i \omega_i ωi的项,其余项都是 m i m_i mi的倍数,也就是说它们 m o d m i mod\ m_i mod mi是为 0 0 0的,最后得到的结果就是 a i a_i ai
m
1
,
m
2
…
m
n
m_1,m_2\dots m_n
m1,m2…mn互质
为了保证是最小正整数解,我们乘以
ω
i
\omega_i
ωi的逆元,这样保证了其不会过大
Code
#define ll long long
#define ull unsigned long long
void ex_gcd (ll a,ll b,ll &x,ll &y)
{
if (!b){ x=1,y=0;return;}
ex_gcd(b,a%b,x,y);
int tmp=x;
x=y,y=tmp-a/b*y;
}
ll mul (ll x,ll y,const ll mod)//快速乘
{
x%=mod,y%=mod;
ll z=(long double)x*y/mod;
ll ans=(ull)x*y-(ull)z*mod;
return (ans+mod)%mod;
}
ll crt (int *a,int *m,int n)
{
ll M=1,ans=0;
for (int i=1;i<=n;++i) M*=m[i];
for (int i=1;i<=n;++i){
ll ni,jk;
ex_gcd(M/m[i],m[i],ni,jk);//ni 逆元
ans=(ans+mul(mul(M/m[i],a[i],M),ni,M))%M;
}
return ans;
}
扩展中国剩余定理(EXCRT)
目的
求最小的正整数 x x x,使其满足
{ x ≡ a 1 ( m o d m ) x ≡ a 2 ( m o d m 2 ) ⋮ x ≡ a n ( m o d m n ) \begin{cases} x\equiv a_{1}\left( mod\ m\right) \\ x\equiv a_{2}\left( mod\ m_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( mod\ m_{n}\right) \end{cases} ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x≡a1(mod m)x≡a2(mod m2)⋮x≡an(mod mn)
其中 m 1 , m 2 … m n m_1,m_2\dots m_n m1,m2…mn不一定互质
解法
对于
C
R
T
CRT
CRT而言,这里的条件变为
m
m
m之间可以不互质了
显然是不能向原来那样直接求了
考虑已经知道了前
i
−
1
i-1
i−1个方程的答案
x
x
x
设前
i
−
1
i-1
i−1个
m
m
m的最小公倍数
l
c
m
(
m
1
,
m
2
…
m
i
−
1
)
=
M
lcm(m1,m2\dots m_{i-1})=M
lcm(m1,m2…mi−1)=M
现在考虑第
i
i
i个方程
x
≡
a
i
(
m
o
d
m
i
)
x\equiv a_i\left(mod\ m_i\right)
x≡ai(mod mi)
我们知道前
i
−
1
i-1
i−1个方程的最小解为
x
x
x,那么其通用解就是
x
+
k
M
x+kM
x+kM
因为
k
M
kM
kM对前
i
−
1
i-1
i−1个
m
m
m取模肯定是等于
0
0
0的
那么考虑了第
i
i
i个方程后的解应也是如上的一个形式
就设为
x
+
k
M
x+kM
x+kM吧
那么我们就是要求关于
k
k
k的这样的方程
k
M
+
x
≡
a
i
(
m
o
d
m
i
)
kM+x\equiv a_i\left(mod\ m_i\right)
kM+x≡ai(mod mi)
其中
x
,
a
i
,
m
i
x,a_i,m_i
x,ai,mi都是已知的
这就是一个简单的同余方程了
k
M
−
p
m
i
=
a
i
−
x
kM-pm_i=a_i-x
kM−pmi=ai−x
其中两个未知数
k
,
p
k,p
k,p
用
e
x
_
g
c
d
ex\_gcd
ex_gcd求解即可
无解条件就是上述方程无解
code
#define ll long long
#define ull unsigned long long
ll ex_gcd (ll a,ll b,ll &x,ll &y)
{
if (!b){ x=1,y=0;return a;}
ll g=ex_gcd(b,a%b,x,y);
int tmp=x;
x=y,y=tmp-a/b*y;
return g;
}
ll mul (ll a,ll b,ll mod)//快速乘
{
a%=mod,b%=mod;
ll c=(long double)a*b/mod;
ll ans=(ull)a*b-(ull)c*mod;
return (ans+mod)%mod;
}
ll ex_crt (ll *a,ll *m,int n)
{
ll ans=a[1]%m[1],M=m[1];
for (int i=2;i<=n;++i){
ll gcd,x,y,c=(a[i]%m[i]-ans%m[i]+m[i])%m[i];
gcd=ex_gcd(M,m[i],x,y);
if (c%gcd) return -1;
x=mul(x,c/gcd,m[i]/gcd);
ll lm=M;
M=M/gcd*m[i];
ans=((ans+mul(x,lm,M)%M)%M+M)%M;
}
return ans;
}
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧