数论,在ACM道路上走的越来越远,提起数论,都是从整除开始,而一元线性同余方程(组)的解,也要从整除起源。
提起整除问题,最负盛名的是欧几里得算法和扩展欧几里得算法,在这里我就不再赘述,详情请见我的博客:
http://blog.csdn.net/qq_27599517/article/details/50888092
而一元线性同余方程(组)的问题的解法源于扩展欧几里得算法。、
对于一元线性同余方程ax≡b(mod c)来说,这个方程等价于ax=by+c,由于y是未知数,所以可以领y=-有,即有ax+by=c。形如上述方程,很显然是扩展欧几里得算法的式子,而满足扩展欧几里得算法的条件是c%gcd(a,b)==0,如果满足这个条件,就可以求解出来x的值。
具体解法如下:
令 g=gcd(a,b);
a=a0×g;
b=b0×g;
所以式子可以改写成为 a0x+b0y=c/g;此时gcd(a,b)=1,运用扩展欧几里得算法可以解出一个x,但x不唯一,x是一个模b的系,所以x的取为
x,x+b0,x+2b0,……x+(g-1)b0。
对于一元线性方程组而言,这个问题就复杂了一些。一元线性方程组是形如
m≡a0(mod b)
m≡a1(mod b)
m≡a2(mod b)
m≡a3(mod b)
⋮
的式子求x的解。不难发现,我们拿出两个式子来 :
m≡a0(mod b0)
m≡a1(mod b1)
不难看出此时式子可以改写为:
m=a0x+b0
m=a1y+b1
所以可以得到一个式子就是 a0x+a1y=b1-b0,这样就成为了扩展欧几里得算法的式子,再用这个x求出m。
这时我们引入第三个式子 m≡a2(mod b2),此时m=a2y+b2;由于引入了新的式子,所以此时m的值也法生变化,姑且将上一个解出的m称之为m0。
因为x的解是一个系,所以有a0(x+a1/gcd(a0,a1)*k)+b0;所以有a0x+(0a1/gcd(a0,a1))k+b0=m。m0=a0x+b0,所以得出一个新的递推式即(a1a2/gcd(a1,a2))k+a2y=b2-m0;
由此可以一步一步求解出x的值
附代码:
long long a1,b1,a2,b2;
int flag=1;//判断是否有解
//a1,b1的值在循环外赋值
for(int i=1;i<n;i++){
if(flag==0)continue;//及时退出
//a2,b在循环内赋值
long long a,b,c;
a=a1,b=a2;
c=b2-b1;
long long g=gcd(a,b);
a/=g,b/=g;
_gcd(a,b,x,y);
if(c%g!=0){
flag=0;
continue;
}
c/=g;
x=((x*c)%b+b)%b;//保证x>0;
x=x*a1+b1;
b1=x;
a1=b*a1;
}
//最后b1是最终解