初学--求解模线性方程组(中国余数定理)。
中国剩余定理,孙子高富帅。
中国剩余定理到求解运用到了扩展欧几里得算法。
求解模线性方程组(中国余数定理)
a=B[1](mod W[1])
a=B[2](mod W[2])
........
a=B[n](mod W[n])
其中W,B已知,W[i]>0且W[i]与W[j]互质, 求a
设m1,m2,…mk是两两互素的正数,则对任意的整数b1,b2,…bk,同余方程组
x1 = b1 mod m1
x2 = b2 mod m2
…
xk = bk mod mk
其解为:
X = (M1’*M1*b1)+(M2’*M2*b2)+…+(Mk’*Mk*bk) mod m;
其中
m = m1*m2*…*mk;
Mi = m / mi;
Mi’是Mi的逆元
注意:这个求解的方法到前提是,w[i],w[j]是互质的。
具体到代码贴一下:(还是比较好理解到)
1 int china(int b[],int m[],int len) 2 { 3 int i,d,x,y,mi,sum=1,hxl=0;//好多变量 4 for(i=1;i<=len;i++) 5 sum=sum*m[i];//sum=m1*m2*m3*.....mn 6 for(i=1;i<=len;i++) 7 { 8 mi=sum/m[i];//Mi=m/mi 9 d=Ex_gcd(m[i],mi,x,y);//y是mi的逆元,为什么是y呢,我感到很困惑。 10 hxl=(hxl+mi*y*b[i])%sum;//..
11 } 12 if(hxl>0) 13 return hxl; 14 else 15 return hxl+sum; 16 }
现在的问题是,当w[i] ,w[j] 不互质的时候,怎么去解决。这个也是我们要解决到问题了。
做到题目里,很少有全部互质到,那就很简单了,直接套模板了,这个你懂了,也是模板。
如何解决??????
合并操作.
先贴一段别人到思路:
假设C ≡ A1 (mod B1),C ≡ A2 (mod B2)。令C = A1 + X1B,那么X1B1 ≡ A2 − A1 (mod B2)。
用扩展欧几里德算法求出X1,也就求出C。令B = lcm(B1, B2),
那么上面两条方程就可以被C’ ≡ C (mod B)代替。迭代直到只剩下一条方程。
有点跳跃性:
C≡A1 (mod B1) ==>C=B1*k1 + A1; //这个容易理解的
C≡A2 (mod B2) ==>C=B2*k2 + A2;
合并一下 B1*k1 + A1 = B2*k2 + A2 ==> B1*k1-B2*k2 = A2-A1;
对比一下扩展欧几里得到式子 ax+by=c ;
则a=B1 ; b= -B2; c=A2-A1;
根据扩展欧几里得可以求的x0,y0;
gcd(B1,B2) = d;
c=A2-A1;
t=B2/d; //扩展欧几里得里也有这个 b=b/d;
x到最小非负解为 x=(x*c/d %t +t)%t; //需要理解一下。可以分两步 x=x*c/d; x=(x%t +t )%t;
那此时就能求出C 了 C=B1*K1 + A1 ==> C=B1*x + A1; //就是带入方程,求出C { C’ ≡ C (mod B) }
B=(B1*B2)/d; //最小公倍数到求法 b=(b1*b2)/gcd(b1,b2);
具体到看一看代码。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 using namespace std; 6 __int64 x, y, t; 7 __int64 egcd(__int64 a, __int64 b) 8 { 9 if (b == 0) 10 { 11 x = 1; 12 y = 0; 13 return a; 14 } 15 else 16 { 17 __int64 e = egcd(b, a % b); 18 t = x; x = y; y = t - a / b * y; 19 return e; 20 } 21 } 22 int main() 23 { 24 //freopen("in.txt", "r", stdin); 25 __int64 m1, m2, r1, r2, d, c, t; 26 bool sb; 27 int n; 28 while (cin >> n) 29 { 30 sb = 0; 31 cin >> m1 >> r1; 32 for (int i = 0; i < n - 1; i++) 33 { 34 cin >> m2 >> r2; 35 if (sb) continue;//一旦有无解情况出现,自然就不用在计算了 36 d = egcd(m1, m2);//Ex_gcd(a,b); 37 c = r2 - r1;//ax+by=(c2-c1) c=c2-c1;//c 是余数 38 if (c % d)//是否有解 39 { 40 sb = 1; 41 continue; 42 } 43 t = m2 / d;//b= b/d; 44 x = (c / d * x % t + t) % t;//x=(x0*c/d % b+b)%b; 45 //求最小到x 46 r1 = m1 * x + r1;//C = A1 + X1B1 ==> A1=C; 47 m1 = m1 * m2 / d;//最小公倍数赋值给m1 C’ ≡ C (mod B) 48 } 49 if (sb) 50 cout << -1 << endl; 51 else 52 cout << r1 << endl; 53 } 54 55 }