中国剩余定理
类似于这样的问题:有一个数,模5余2,模7余3,模13余8,……,求这个数是多少?
实质上就是求一个模线性方程组。
{x≡a1(modr1)x≡a2(modr2)x≡a3(modr3)…x≡ak(modrk)\begin{cases} x \equiv a_1 \pmod {r_1} \\ x\equiv a_2 \pmod {r_2} \\ x\equiv a_3 \pmod{r_3} \\ \dots \\ x \equiv a_k \pmod{r_k} \end{cases}⎩⎨⎧x≡a1(modr1)x≡a2(modr2)x≡a3(modr3)…x≡ak(modrk)
其中,r1,r2,…,rkr_1,r_2,\dots,r_kr1,r2,…,rk互质。
中国剩余定理就是解决这种模数互质的模线性方程组的。
因为r1,r2,…,rkr_1,r_2,\dots,r_kr1,r2,…,rk互质,所以,对于rir_iri,设Ai=∏j≠irjA_i=\prod_{ j\neq i}r_jAi=∏j=irj,则Ai,riA_i,r_iAi,ri是互质的,则必存在一个整数cic_ici,使得ci∗Ai%ri=1c_i*A_i \%r_i=1ci∗Ai%ri=1,则设xi=ai∗ci∗Aix_i=a_i*c_i*A_ixi=ai∗ci∗Ai,则xi%ri=aix_i\%r_i=a_ixi%ri=ai。因为AiA_iAi是除了rir_iri以外的其他rrr值的最小公倍数,所以,xix_ixi 模其他的r,余数都为0,只有模rir_iri时,余数为aia_iai。
这就是说,把xix_ixi加到满足其他方程(比如第j个方程,j≠ij\neq ij=i)的解xjx_jxj上,则(xi+xj)(x_i+x_j)(xi+xj) 也满足方程iii。同理,如果xjx_jxj 也是这么求出来的,则(xi+xj)(x_i+x_j)(xi+xj)也满足方程iii。
那么,我们对于每一个方程,都按照这个方法求出来该方程的解。把这些解累加起来,你会发现,这个和仍然满足每一个方程。
则x=∑i=1kai∗ci∗Aix=\sum\limits _{i=1}^k a_i*c_i*A_ix=i=1∑kai∗ci∗Ai
对于x,如果我们加上所有的r值的最小公倍数,它仍然满足所有方程。
所以,只有存在x,则意味着有无穷多组解。
通解为:
x=∑i=1kai∗ci∗Ai+p∗∏i=1krix=\sum\limits _{i=1}^k a_i*c_i*A_i+p*\prod_{i=1}^kr_ix=i=1∑kai∗ci∗Ai+p∗∏i=1kri
其中,p是任意整数。
扩展中国剩余定理
中国剩余定理采用的是构造法做的,要求模数互质。但是如果模数不互质,怎么办呢?
那么这就是扩展中国剩余定理要解决的问题了。
{x≡a1(modr1)x≡a2(modr2)x≡a3(modr3)…x≡ak(modrk)\begin{cases} x \equiv a_1 \pmod {r_1} \\ x\equiv a_2 \pmod {r_2} \\ x\equiv a_3 \pmod{r_3} \\ \dots \\ x \equiv a_k \pmod{r_k} \end{cases}⎩⎨⎧x≡a1(modr1)x≡a2(modr2)x≡a3(modr3)…x≡ak(modrk)
首先取方程组的前两个方程:
x=k∗r1+a1=p∗r2+a2x=k*r_1+a_1=p*r_2+a_2x=k∗r1+a1=p∗r2+a2
k∗r1−p∗r2=(a2−a1)k*r_1-p*r_2=(a_2-a_1)k∗r1−p∗r2=(a2−a1)
这个形如ax+by=cax+by=cax+by=c的不定方程,用扩展欧几里得算法即可。
当gcd(r1,r2)gcd(r_1,r_2)gcd(r1,r2)不能整除a2−a1a_2-a_1a2−a1时,方程组无解。
否则,根据exgcd,求出k0k_0k0,满足k0∗r1−p∗r2=(a2−a1)k_0*r_1-p*r_2=(a_2-a_1)k0∗r1−p∗r2=(a2−a1)。k的通解为:k=k0+b∗(r2/gcd(r1,r2))k=k_0+b*(r_2/gcd(r_1,r_2))k=k0+b∗(r2/gcd(r1,r2))
代入到方程组x=k∗r1+a1x=k*r_1+a_1x=k∗r1+a1中,则有x=(k0+b∗(r2/gcd(r1,r2)))∗r1+a1=k0∗r1+b∗lcm(r1,r2)+a1x=(k_0+b*(r_2/gcd(r_1,r_2)))*r_1+a_1=k_0*r_1+b*lcm(r_1,r_2)+a_1x=(k0+b∗(r2/gcd(r1,r2)))∗r1+a1=k0∗r1+b∗lcm(r1,r2)+a1
其中b为任意整数。
即:x≡(k0∗r1)+a1(modlcm(r1,r2))x \equiv(k_0*r_1)+a_1 \pmod{lcm(r_1,r_2)}x≡(k0∗r1)+a1(modlcm(r1,r2))
这个方程相当于合并了原来的两个方程,而形式上又和原来的方程一致。
继续采用这个方法,不断地合并方程组中的两个方程,直到最后合并为一个方程,则得到了x的通解了。
注意在这个过程中,要注意求出的k0k_0k0是k∗r1−p∗r2=(a2−a1)k*r_1-p*r_2=(a_2-a_1)k∗r1−p∗r2=(a2−a1)的解,而不是k∗r1−p∗r2=gcd(r1,r2)k*r_1-p*r_2=gcd(r_1,r_2)k∗r1−p∗r2=gcd(r1,r2)的解。前者是后者的倍数。
一道例题:poj2891 (扩展中国剩余定理模板题)
给出一个模线性方程组,模数不互质,求方程的最小正整数解。如果无解,输出-1.
// ax+by=c
// x%a1=r1
// x%a2=r2
// x=k*a1+r1=p*a2+r2
// k*a1+q*a2=r2-r1
// a1,a2,r2-r1已知,所以可以通过exgcd求出k和q。
// 求出一个k值,设为k0.
// k=k0+a2/gcd(a1,a2)
// x=k*a1+r1=(k0+b*a2/(gcd(a1,a2)))*a1+r1=k0*a1+b*lcm(a1,a2)+r1
// x的通解 x=lcm(a1,a2)*b+k0*a1+r1
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long int
#define abs(a) (a>0?a:-(a))
LL m,ans;
#define MAXN 1005
LL arr[MAXN],r[MAXN];
LL a,b,d,x,y,lcm;
void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(!b)
{
d=a,x=1,y=0;
}
else
{
exgcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
bool noans;
int main()
{
while(scanf("%d",&m)!=-1)
{
noans=0;
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&arr[i],&r[i]);
}
for(int i=1;i<m;i++)
{
exgcd(arr[i],arr[i+1],d,x,y);
if(abs(r[i+1]-r[i])%d)
{
noans=1;
break;
}
x=(x*((r[i+1]-r[i])/d)%(arr[i+1]/d)+arr[i+1]/d)%(arr[i+1]/d);
lcm=arr[i]*arr[i+1]/d;
arr[i+1]=lcm,r[i+1]=(x*arr[i]+r[i])%lcm;
}
if(noans==0)
ans=r[m];
else
ans=-1;
printf("%lld\n",ans);
}
return 0;
}