扩展中国剩余定理(EXCRT)
中国剩余定理可以解形如下面的一元线性同余方程组:
{ans≡x1(moda1)ans≡x2(moda2)ans≡x3(moda3)...ans≡xn(modan) \left\{\begin{matrix}
ans\equiv x_1\pmod{a_1} \\
ans\equiv x_2\pmod{a_2} \\
ans\equiv x_3\pmod{a_3}\\
.\\
.\\
.\\
ans\equiv x_n\pmod{a_n}
\end{matrix}\right.⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧ans≡x1(moda1)ans≡x2(moda2)ans≡x3(moda3)...ans≡xn(modan)
其中a1,a2,a3…an两两互素。
如果a1,a2,a3…an不两两互素时,就不能利用中国剩余定理去解上述方程组了。因为不存在另外n-1个ai的乘积关于剩下一个数的逆元。
我们先考虑将如下方程组合并成一个方程
{ans≡x1(moda1)ans≡x2(moda2)\left\{\begin{matrix}
ans\equiv x_1\pmod{a_1} \\
ans\equiv x_2\pmod{a_2} \\
\end{matrix}\right.{ans≡x1(moda1)ans≡x2(moda2)
该方程存在唯一解ans,使得ans=m1a1+x1=m2a2+x2ans=m_1a_1+x_1=m_2a_2+x_2ans=m1a1+x1=m2a2+x2成立。
所以有方程
m1a1+x1=m2a2+x2m_1a_1+x_1=m_2a_2+x_2m1a1+x1=m2a2+x2即
m1a1−m2a2=x2−x1m_1a_1-m_2a_2=x_2-x_1m1a1−m2a2=x2−x1
成立。
如果有gcd(a1,a2)∣(x2−x1)gcd(a_1,a_2)|(x_2-x_1)gcd(a1,a2)∣(x2−x1),我们则可以通过扩展欧几里得算法求得整数解。
否则无解。
在求得一组解(m1,m2)后,可以将上述方程组转化为以下方程:
ans≡X(modlcm(a1,a2))ans\equiv X\pmod {lcm(a_1,a_2)}ans≡X(modlcm(a1,a2))
其中X=m1a1+b1=m2a2+b2X=m_1a_1+b_1=m_2a_2+b_2X=m1a1+b1=m2a2+b2。
显然X是上述方程组的一个特解。
设M=lcm(a1,a2)M=lcm(a_1,a_2)M=lcm(a1,a2),那么通解为X′=kM+XX'=kM+XX′=kM+X
可以将上述结论推广至由k个同余方程组成的一元线性同余方程组。
算法流程如下:
设xk为前k个一元线性同余方程合并后的一个特解,xk+1为第k+1个同余方程的特解。ak为前k个一元线性同余方程合并后的模数,即lcm(a1,a2,...,ak)lcm(a1,a2,...,a_k)lcm(a1,a2,...,ak)。ak+1为第k+1个同余方程的模数。
for k=1 to n:for\space k=1\space to\space n:for k=1 to n:
1、解方程akx−ak+1y=gcd(ak,ak+1)a_kx-a_{k+1}y=gcd(a_k,a_{k+1})akx−ak+1y=gcd(ak,ak+1)。
2、若gcd(ak,ak+1)∣(xk+1−xk)gcd(a_k,a_{k+1})|(x_{k+1}-x_k)gcd(ak,ak+1)∣(xk+1−xk),则可以求出akx−ak+1y=xk+1−xka_kx-a_{k+1}y=x_{k+1}-x_kakx−ak+1y=xk+1−xk的一个特解x′=xk+1−xkgcd(ak,ak+1)xx'=\frac{x_{k+1}-x_k}{gcd(a_k,a_{k+1})}xx′=gcd(ak,ak+1)xk+1−xkx;否则无解,算法结束。
3、合并前k+1个方程的后一个特解为xk+1=akx′+xkx_{k+1}=a_kx'+x_kxk+1=akx′+xk,
4、合并前k+1个方程的后的模数为lcm(ak,ak+1)lcm(a_k,a_{k+1})lcm(ak,ak+1)
知道对于方程ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b),由一对特解(x,y),那么由通解X,Y,X=k⋅bgcd(a,b)+x,Y=k⋅agcd(a,b)+yX=k\cdot\frac{b}{gcd(a,b)}+x,Y=k\cdot\frac{a}{gcd(a,b)}+yX=k⋅gcd(a,b)b+x,Y=k⋅gcd(a,b)a+y。
在上述算法流程中,如果xk+1−xkgcd(ak,ak+1)\frac{x_{k+1}-x_k}{gcd(a_k,a_{k+1})}gcd(ak,ak+1)xk+1−xk较大,直接与x相乘可能会造成溢出。我们可以把x’限制在[0ak+1gcd(ak,ak+1)][0\frac{a_{k+1}}{gcd(a_k,a_{k+1})}][0gcd(ak,ak+1)ak+1]中,通过慢速乘法(类似与快速幂)防止数据溢出。
模板代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b){
x=1;y=0;d=a;return ;
}
else{
exgcd(b,a%b,d,y,x);y-=(a/b)*x;
}
}
ll mul(ll a,ll b,ll mod)
{
ll ans=0;
while(b)
{
if(b&1)ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
int main(void)
{
int n;
scanf("%d",&n);
ll b1=0,a1=1;
ll b2,a2;
while(n--)
{
scanf("%lld%lld",&a2,&b2);
ll x,y,d,t;//求解x*a1+b1=b2(mod a2)
t=((b2-b1)%a2+a2)%a2;//x*a1=b2-b1(mod a2)
exgcd(a1,a2,d,x,y);//求解x*a1+y*a2=gcd(a1,a2)
ll g=a2/d;
x=mul(x,t/d,g);
b1+=x*a1;
a1*=a2/d;//lcm
b1=(b1%a1+a1)%a1;
}
printf("%lld\n",b1);
}

本文详细介绍了扩展中国剩余定理(EXCRT),用于解决不完全互素的一元线性同余方程组。通过扩展欧几里得算法找到整数解,并给出算法流程,包括如何避免数据溢出。最后提供了模板代码供参考。
1197

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



