中国剩余定理

说到中国剩余定理就不能不提一些前期的一些知识点:

1.利用欧几里得算法求整数系数已从不定方程ax+by = c的解:

对于这个不定方程的解有两种程序:

(1)无递归的实现方式:

//扩展的欧几里得算法无递归程序: __int64 extend_gcd_w_dg(__int64 a, __int64 b, __int64 &x, __int64 &y) { __int64 x0, x1, x2, y0, y1, y2; __int64 r0, r1, r2, q; if(a==0 && b==0)//当a与b的最大公因数不存在 { x = 0; y = 1; return -1; } if(a==0 && b!=0)//a=0,就不存在a的乘法逆元 { x = 0; y = 0; return a; } if(b==0 && a!=0)//b=0,不存在b的乘法逆元 { x = 1; y = 0; return a; } if(a!=0 && b!=0) { x0 = 0; x1 = 1; r0 = a; y0 = 1; r1 = b; r2 = r0%r1; y1 = 0 - r0/r1; x2 = 1; y2 = y1; while((r1%r2)!=0) { r0 = r1; r1 = r2; q = r0/r1; x2 = x0 - x1*q; y2 = y0 - y1*q; x0 = x1; x1 = x2; y0 = y1; y1 = y2; r2 = r0%r1; } x = x2; y = y2; return r2; } } 

(2)递归的实现方式:

//最大公因数的扩展欧几里得算法的递归程序 /********************** 输入:a,b 输出:返回:d=gcd(a,b)和对应于等于ax+by=d中的x,y /**********************/ __int64 extend_gcd(__int64 a, __int64 b, __int64 &x, __int64 &y) { __int64 t, m; if((b==0) && (a==0)) return -1;//表示无最大公因数 if(b==0) { x = 1; y = 0; return a; } else { m = extend_gcd(b, a % b, x, y); t = x; x = y; y = t - (a/b)*y; } return m; } 

2.求 mod m 的逆元素算法:

定理:对整数a,m(m>0),如果存在整数b,满足ab≡1(mod m),那么称b是a的模m乘法逆元。

也有两种方法来求解逆元元素:

(1)利用扩展欧几里得算法来求解:

//求逆元的递归程序 __int64 mod_reverse_digui(__int64 a, __int64 m) { __int64 x, y, gcd; gcd = extend_gcd_w_dg(a, m, x, y); if(gcd == 1) { if(x<0) x = (x%m+m)%m; return x; } else return 0; } 

(2)利用无递归的程序:

//求mod m的逆元素的无递归程序: __int64 mod_reverse(__int64 a, __int64 m) { __int64 y = 0, x = 1, r = a%m, q, t, mm = m; if(r<0) r = r+m; while((m%r) != 0) { a = m; m = r; q = a/m; r = a%m; t = x; x = y-x*q; y = t; } if(r!=1) return 0; if(x<0) x = x+mm; return x; } 

 

3.中国剩余定理的内容如下:
设m 1,m 2,....,m n  是两两互素的n个正整数,记m=m 1m 2....m n,M i = m/m i,1<=i<=n,那么,下列模线性方程组:
 x ≡ b 1(mod m 1)
 x ≡ b 2(mod m 2)
 .
 .
 .
 x ≡ b n(mod m n)
的解为x 0 = (b 1M 1y 1 + b 2M 2y 2 + b 3M 3y 3 + ... + b nM ny n)mod m,其中,y i是M iy i ≡ 1(mod m i)的解,i=1,2,3...,n.
中国剩余定理程序如下:
//中国剩余定理的程序如下: int n; __int64 ChinaRemainder(int m0[], int b[]) { __int64 d, x, y, m=1, a=0; int i; for(i=1; i<=n; i++) m = m*m0[i]; for(i=1; i<=n; i++) { __int64 MM = m/m0[i]; // extend_gcd(MM, m0[i], x, y); // x = mod_reverse(MM, m0[i]); x = mod_reverse_digui(MM, m0[i]); a = (a+MM*x*b[i])%m; } return a; } 
总体程序实现如下:
//中国剩余定理 /* 设m1,m2,...,mn是两两互素的n个正整数,记m=m1m2..mn,Mi=m/mi,1<=i<=n,那么下列模线性方程组: x=b1(mod m1) x=b2(mod m2) . . . x=bn(mod mn) 求出这个方程组的解 */ #include<stdio.h> #include<string.h> #include<math.h> #define MAXN 100 //最大公因数的扩展欧几里得算法的递归程序 /********************** 输入:a,b 输出:返回:d=gcd(a,b)和对应于等于ax+by=d中的x,y /**********************/ __int64 extend_gcd(__int64 a, __int64 b, __int64 &x, __int64 &y) { __int64 t, m; if((b==0) && (a==0)) return -1;//表示无最大公因数 if(b==0) { x = 1; y = 0; return a; } else { m = extend_gcd(b, a % b, x, y); t = x; x = y; y = t - (a/b)*y; } return m; } //扩展的欧几里得算法无递归程序: __int64 extend_gcd_w_dg(__int64 a, __int64 b, __int64 &x, __int64 &y) { __int64 x0, x1, x2, y0, y1, y2; __int64 r0, r1, r2, q; if(a==0 && b==0)//当a与b的最大公因数不存在 { x = 0; y = 1; return -1; } if(a==0 && b!=0)//a=0,就不存在a的乘法逆元 { x = 0; y = 0; return a; } if(b==0 && a!=0)//b=0,不存在b的乘法逆元 { x = 1; y = 0; return a; } if(a!=0 && b!=0) { x0 = 0; x1 = 1; r0 = a; y0 = 1; r1 = b; r2 = r0%r1; y1 = 0 - r0/r1; x2 = 1; y2 = y1; while((r1%r2)!=0) { r0 = r1; r1 = r2; q = r0/r1; x2 = x0 - x1*q; y2 = y0 - y1*q; x0 = x1; x1 = x2; y0 = y1; y1 = y2; r2 = r0%r1; } x = x2; y = y2; return r2; } } //求mod m的逆元素的无递归程序: __int64 mod_reverse(__int64 a, __int64 m) { __int64 y = 0, x = 1, r = a%m, q, t, mm = m; if(r<0) r = r+m; while((m%r) != 0) { a = m; m = r; q = a/m; r = a%m; t = x; x = y-x*q; y = t; } if(r!=1) return 0; if(x<0) x = x+mm; return x; } //求逆元的递归程序 __int64 mod_reverse_digui(__int64 a, __int64 m) { __int64 x, y, gcd; gcd = extend_gcd_w_dg(a, m, x, y); if(gcd == 1) { if(x<0) x = (x%m+m)%m; return x; } else return 0; } //中国剩余定理的程序如下: int n; __int64 ChinaRemainder(int m0[], int b[]) { __int64 d, x, y, m=1, a=0; int i; for(i=1; i<=n; i++) m = m*m0[i]; for(i=1; i<=n; i++) { __int64 MM = m/m0[i]; // extend_gcd(MM, m0[i], x, y); // x = mod_reverse(MM, m0[i]); x = mod_reverse_digui(MM, m0[i]); a = (a+MM*x*b[i])%m; } return a; } int main() { freopen("in.txt", "r", stdin); int i; __int64 ans; int b[MAXN], m[MAXN]; while(scanf("%d", &n) != EOF) { for(i=1; i<=n; i++) { scanf("%d %d", &b[i], &m[i]); } printf("%I64d/n", ChinaRemainder(m, b)); } return 0; } /* 2 2 5 3 13 4 1 3 -1 5 2 7 -2 11 */ 

 

 

你可能感兴趣的:(c,算法,扩展)