中国剩余定理求解同余线性方程组—(互素和非互素的情况)

本文详细介绍了中国剩余定理的基本概念及其应用,包括求解一次同余方程组的方法,并提供了互质及非互质情况下的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


中国剩余定理

     中国剩余定理是中国古代求解一次同余方程组的方法,是数论中的一个重要定理。

     设m1,m2,m3,...,mk是两两互素的正整数,即gcd(mi,mj)=1,i!=j,i,j=1,2,3,...,k.

则同余方程组:

x = a1 (mod n1)

x = a2 (mod n2)

...

x = ak (mod nk)

模[n1,n2,...nk]有唯一解,即在[n1,n2,...,nk]的意义下,存在唯一的x,满足:

x = ai mod [n1,n2,...,nk], i=1,2,3,...,k。

解可以写为这种形式:

x = sigma(ai* mi*mi') mod(N)

      其中N=n1*n2*...*nk,mi=N/ni,mi'为mi在模ni乘法下的逆元。

 

中国剩余定理非互质版

    中国剩余定理求解同余方程要求模数两两互质,在非互质的时候其实也可以计算,这里采用的是合并方程的思想。下面是详细推导。



 

FZU1402 中国剩余定理

Cpp代码  复制代码  收藏代码
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. using namespace std;  
  5. typedef __int64 int64;  
  6. int64 a[15],b[15];  
  7.   
  8. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  9. {  
  10.     if(b==0)  
  11.     {  
  12.         x=1,y=0;  
  13.         return a;  
  14.     }  
  15.     int64 d = Extend_Euclid(b,a%b,x,y);  
  16.     int64 t = x;  
  17.     x = y;  
  18.     y = t - a/b*y;  
  19.     return d;  
  20. }  
  21. //求解模线性方程组x=ai(mod ni)  
  22. int64 China_Reminder(int len, int64* a, int64* n)  
  23. {  
  24.     int i;  
  25.     int64 N = 1;  
  26.     int64 result = 0;  
  27.     for(i = 0; i < len; i++)  
  28.         N = N*n[i];  
  29.     for(i = 0; i < len; i++)  
  30.     {  
  31.         int64 m = N/n[i];  
  32.         int64 x,y;  
  33.         Extend_Euclid(m,n[i],x,y);  
  34.         x = (x%n[i]+n[i])%n[i];  
  35.         result = (result + m*a[i]*x%N)%N;  
  36.     }  
  37.     return result;  
  38. }  
  39.   
  40. int main()  
  41. {  
  42.     int n;  
  43.     while(scanf("%d",&n)!=EOF)  
  44.     {  
  45.         for(int i = 0; i < n; i++)  
  46.             scanf("%I64d %I64d",&a[i],&b[i]);  
  47.         printf("%I64d\n",China_Reminder(n,b,a));  
  48.     }  
  49.     return 0;  
  50. }  
[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. using namespace std;  
  5. typedef __int64 int64;  
  6. int64 a[15],b[15];  
  7.   
  8. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  9. {  
  10.     if(b==0)  
  11.     {  
  12.         x=1,y=0;  
  13.         return a;  
  14.     }  
  15.     int64 d = Extend_Euclid(b,a%b,x,y);  
  16.     int64 t = x;  
  17.     x = y;  
  18.     y = t - a/b*y;  
  19.     return d;  
  20. }  
  21. //求解模线性方程组x=ai(mod ni)  
  22. int64 China_Reminder(int len, int64* a, int64* n)  
  23. {  
  24.     int i;  
  25.     int64 N = 1;  
  26.     int64 result = 0;  
  27.     for(i = 0; i < len; i++)  
  28.         N = N*n[i];  
  29.     for(i = 0; i < len; i++)  
  30.     {  
  31.         int64 m = N/n[i];  
  32.         int64 x,y;  
  33.         Extend_Euclid(m,n[i],x,y);  
  34.         x = (x%n[i]+n[i])%n[i];  
  35.         result = (result + m*a[i]*x%N)%N;  
  36.     }  
  37.     return result;  
  38. }  
  39.   
  40. int main()  
  41. {  
  42.     int n;  
  43.     while(scanf("%d",&n)!=EOF)  
  44.     {  
  45.         for(int i = 0; i < n; i++)  
  46.             scanf("%I64d %I64d",&a[i],&b[i]);  
  47.         printf("%I64d\n",China_Reminder(n,b,a));  
  48.     }  
  49.     return 0;  
  50. }  

 

 

 

POJ2891 非互质版

Cpp代码  复制代码  收藏代码
  1. /** 
  2. 中国剩余定理(不互质) 
  3. */  
  4. #include <iostream>  
  5. #include <cstdio>  
  6. #include <cstring>  
  7. using namespace std;  
  8. typedef __int64 int64;  
  9. int64 Mod;  
  10.   
  11. int64 gcd(int64 a, int64 b)  
  12. {  
  13.     if(b==0)  
  14.         return a;  
  15.     return gcd(b,a%b);  
  16. }  
  17.   
  18. int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)  
  19. {  
  20.     if(b==0)  
  21.     {  
  22.         x=1,y=0;  
  23.         return a;  
  24.     }  
  25.     int64 d = Extend_Euclid(b,a%b,x,y);  
  26.     int64 t = x;  
  27.     x = y;  
  28.     y = t - a/b*y;  
  29.     return d;  
  30. }  
  31.   
  32. //a在模n乘法下的逆元,没有则返回-1  
  33. int64 inv(int64 a, int64 n)  
  34. {  
  35.     int64 x,y;  
  36.     int64 t = Extend_Euclid(a,n,x,y);  
  37.     if(t != 1)  
  38.         return -1;  
  39.     return (x%n+n)%n;  
  40. }  
  41.   
  42. //将两个方程合并为一个  
  43. bool merge(int64 a1, int64 n1, int64 a2, int64 n2, int64& a3, int64& n3)  
  44. {  
  45.     int64 d = gcd(n1,n2);  
  46.     int64 c = a2-a1;  
  47.     if(c%d)  
  48.         return false;  
  49.     c = (c%n2+n2)%n2;  
  50.     c /= d;  
  51.     n1 /= d;  
  52.     n2 /= d;  
  53.     c *= inv(n1,n2);  
  54.     c %= n2;  
  55.     c *= n1*d;  
  56.     c += a1;  
  57.     n3 = n1*n2*d;  
  58.     a3 = (c%n3+n3)%n3;  
  59.     return true;  
  60. }  
  61.   
  62. //求模线性方程组x=ai(mod ni),ni可以不互质  
  63. int64 China_Reminder2(int len, int64* a, int64* n)  
  64. {  
  65.     int64 a1=a[0],n1=n[0];  
  66.     int64 a2,n2;  
  67.     for(int i = 1; i < len; i++)  
  68.     {  
  69.         int64 aa,nn;  
  70.         a2 = a[i],n2=n[i];  
  71.         if(!merge(a1,n1,a2,n2,aa,nn))  
  72.             return -1;  
  73.         a1 = aa;  
  74.         n1 = nn;  
  75.     }  
  76.     Mod = n1;  
  77.     return (a1%n1+n1)%n1;  
  78. }  
  79. int64 a[1000],b[1000];  
  80. int main()  
  81. {  
  82.     int i;  
  83.     int k;  
  84.     while(scanf("%d",&k)!=EOF)  
  85.     {  
  86.         for(i = 0; i < k; i++)  
  87.             scanf("%I64d %I64d",&a[i],&b[i]);  
  88.         printf("%I64d\n",China_Reminder2(k,b,a));  
  89.     }  
  90.     return 0;  
  91. }  
### 中国剩余定理的大数实现 #### 定义与背景 中国剩余定理是一种用于解决模线性方程组的经典方法,特别适用于模数情况[^1]。该定理的核心在于通过分解问题并逐步求解的方式找到满足条件的唯一解。 对于大数运算场景下的中国剩余定理实现,通常会借助专门设计的大数处理库来完成复杂的数值计算。例如,在实际应用中可以采用 MIRACL (Multiprecision Integer and Rational Arithmetic C/C++ Library) 或其他类似的工具支持高效的大数操作[^3]。 --- #### 数学基础 假设给定一组两两质的正整数 \( m_1, m_2, \dots, m_k \),以及对应的数序列 \( a_1, a_2, \dots, a_k \),则存在唯一的最小负整数 \( x \) 满足以下同余方程组: \[ \begin{aligned} &x \equiv a_1 \pmod {m_1}, \\ &x \equiv a_2 \pmod {m_2}, \\ &\vdots \\ &x \equiv a_k \pmod {m_k}. \end{aligned} \] 其中,\( M = m_1 \cdot m_2 \cdots m_k \) 是所有模数的乘积,而每个子项定义为 \( M_i = M / m_i \)[^4]。进一步地,可以通过扩展欧几里得算法求出逆元 \( y_i \),使得 \( M_i \cdot y_i \equiv 1 \pmod {m_i} \) 成立。最终通解形式可表示为: \[ x = \sum_{i=1}^{k}{(a_i \cdot M_i \cdot y_i)} \pmod M. \] --- #### 算法伪代码描述 以下是基于上述理论构建的一个通用算法框架,适合应用于大数环境: ```python def chinese_remainder_theorem(moduli, remainders): """ 使用中国剩余定理求解线性方程组。 参数: moduli -- 列表,存储各模数 mi remainders -- 列表,存储对应数 ai 返回值: 整数型变量,代表所求数字 x 的最小负解。 """ from math import gcd total_modulus = 1 result = 0 # 验证输入数据合法性 assert len(moduli) == len(remainders), "Moduli Remainders 应具有相长度" for i in range(len(moduli)): for j in range(i + 1, len(moduli)): if gcd(moduli[i], moduli[j]) != 1: raise ValueError(f"模数 {moduli[i]} {moduli[j]} ") # 计算总模数 M 及其分量 Mi for modulus in moduli: total_modulus *= modulus # 构造特解部分 for modulus, remainder in zip(moduli, remainders): partial = total_modulus // modulus # Mi = M / mi inverse = pow(partial, -1, modulus) # yi ≡ inv(Mi, mi) result += remainder * partial * inverse # 更新结果 return result % total_modulus # 返回最小负解 ``` 此函数实现了标准版本的 CRT 方法,并且兼容 Python 中内置的支持大整数幂次取模运算的功能 `pow(base, exp, mod)` 来替代传统方式寻找乘法逆元的过程。 --- #### 示例程序运行说明 考虑题目提到的例子:“一个整数除以三二,除以五三,除以七二”,即已知参数列表分别为 `[3, 5, 7]` `[2, 3, 2]` 。调用上面定义好的功能模块即可得到解答过程如下所示: ```python if __name__ == "__main__": mods = [3, 5, 7] rems = [2, 3, 2] solution = chinese_remainder_theorem(mods, rems) print(solution) # 输出应为 23 ``` 执行完毕之后将会打印出正确答案——数字 **23** ,验证无误! --- #### 注意事项 当面对超大规模的数据集或者更高精度需求时,则可能需要引入外部依赖包比如 GMPY2 提供更高效的底层优化机制;另外还需注意边界情况处理如空集合传入等问题以免引发异常中断行为发生。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值