求解同余方程组
{ x ≡ a 1 ( m o d    m 1 ) x ≡ a 2 ( m o d    m 2 ) x ≡ a 3 ( m o d    m 3 ) . . . x ≡ a k ( m o d    m k ) \begin{cases} x\equiv\ a_1(\mod m_1) \quad \\ x\equiv\ a_2(\mod m_2) \quad \\ x\equiv\ a_3(\mod m_3) \quad \\ ...\quad \\ x\equiv\ a_k(\mod m_k) \quad \\ \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x≡ a1(modm1)x≡ a2(modm2)x≡ a3(modm3)...x≡ ak(modmk)
其中 m 1 , m 2 , m 3 . . . m k m_1,m_2,m_3...m_k m1,m2,m3...mk为两两互质的整数
求x的最小非负整数解
令 M = ∏ i = 1 k m i M=\prod_{i=1}^km_i M=∏i=1kmi,即M是所有 m i m_i mi的最小公倍数
t i t_i ti为同余方程 M m i t i ≡ 1 ( m o d    m i ) \frac{M}{m_i}t_i \equiv\ 1(\mod m_i) miMti≡ 1(modmi)的最小非负整数解
则有一个解为 x = ∑ i = 1 k a i M m i t i x=\sum_{i=1}^ka_i\frac{M}{m_i}t_i x=∑i=1kaimiMti
通解为 x + i ∗ M ( i ∈ Z ) x+i*M(i\in Z) x+i∗M(i∈Z)
特别的,最小非负整数解为 ( x (x (x% M + M ) M+M) M+M)% M M M
因为 M m i \frac{M}{m_i} miM是除 m i m_i mi之外的所有m的倍数
所以 ∀ k ̸ = i , a i M m i t i ≡ 0 ( m o d    m k ) \forall k \not= i, a_i\frac{M}{m_i}t_i \equiv 0(\mod m_k) ∀k̸=i,aimiMti≡0(modmk)
又有 M m i t i ≡ 1 ( m o d    m i ) \frac{M}{m_i}t_i \equiv\ 1(\mod m_i) miMti≡ 1(modmi)
两边同时乘 a i a_i ai得 a i M m i t i ≡ a i ( m o d    m i ) a_i\frac{M}{m_i}t_i \equiv a_i(\mod m_i) aimiMti≡ai(modmi)
带入 x = ∑ i = 1 k a i M m i t i x=\sum_{i=1}^ka_i\frac{M}{m_i}t_i x=∑i=1kaimiMti
原方程组成立
——算法竞赛进阶指南
t i t_i ti同余式的求解可以用扩展欧几里得
void exgcd(int a,int b,int &x,int &y)
{
if(b==0){ x=1; y=0; return;}
exgcd(b,a%b,x,y);
int tp=x;
x=y; y=tp-a/b*y;
}
int china()
{
int ans=0,lcm=1,x,y;
for(int i=1;i<=k;++i) lcm*=b[i];
for(int i=1;i<=k;++i)
{
int tp=lcm/b[i];
exgcd(tp,b[i],x,y);
x=(x%b[i]+b[i])%b[i];//x要为最小非负整数解
ans=(ans+tp*x*a[i])%lcm;
}
return (ans+lcm)%lcm;
}
一道模板题
求解同余方程组
{ x ≡ a 1 ( m o d    m 1 ) x ≡ a 2 ( m o d    m 2 ) x ≡ a 3 ( m o d    m 3 ) . . . x ≡ a k ( m o d    m k ) \begin{cases} x\equiv\ a_1(\mod m_1) \quad \\ x\equiv\ a_2(\mod m_2) \quad \\ x\equiv\ a_3(\mod m_3) \quad \\ ...\quad \\ x\equiv\ a_k(\mod m_k) \quad \\ \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x≡ a1(modm1)x≡ a2(modm2)x≡ a3(modm3)...x≡ ak(modmk)
其中 m 1 , m 2 , m 3 . . . m k m_1,m_2,m_3...m_k m1,m2,m3...mk为不一定两两互质的整数
求x的最小非负整数解
假设已经求出前k-1个方程组成的同余方程组的一个解为x
且有 M = ∏ i − 1 k − 1 m i M=\prod_{i-1}^{k-1}m_i M=∏i−1k−1mi
则前k-1个方程的方程组通解为 x + i ∗ M ( i ∈ Z ) x+i*M(i\in Z) x+i∗M(i∈Z)
那么对于加入第k个方程后的方程组
我们就是要求一个正整数t,使得
x + t ∗ M ≡ a k ( m o d    m k ) x+t*M \equiv a_k(\mod m_k) x+t∗M≡ak(modmk)
转化一下上述式子得
t ∗ M ≡ a k − x ( m o d    m k ) t*M \equiv a_k-x(\mod m_k) t∗M≡ak−x(modmk)
对于这个式子我们已经可以通过扩展欧几里得求解t
若该同余式无解,则整个方程组无解
若有,则前k个同余式组成的方程组的一个解解为 x k = x + t ∗ M x_k=x+t*M xk=x+t∗M
所以整个算法的思路就是求解k次扩展欧几里得
lt exgcd(lt a,lt b,lt &x,lt &y)
{
if(b==0){x=1;y=0;return a;}
lt gcd=exgcd(b,a%b,x,y);
lt tp=x;
x=y; y=tp-a/b*y;
return gcd;
}
lt excrt()
{
lt x,y,k;
lt M=bi[1],ans=ai[1];
for(int i=2;i<=n;i++)
{
lt a=M,b=bi[i],c=(ai[i]-ans%b+b)%b;
lt gcd=exgcd(a,b,x,y),bg=b/gcd;
if(c%gcd!=0) return -1;
x=mul(x,c/gcd,bg);
ans+=x*M;
M*=bg;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
一道模板题