ACM 进阶学习第一课----同余相关之中国剩余定理

原文链接:http://blog.csdn.net/hu1020935219/article/details/14112149

问题引入

"物不知数"问题:
今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?
答曰:'二十三.'
术曰:三三数之剩二,置一百四十,五五数之剩三,置六十三,七七数之剩二,置三十,并之,得二百三十三,以二百一十减之,即得.凡三三数之剩一,则置七十,五五数之剩一,则置二十一,七七数之剩一,则置十五,即得." 
 --孙子算经

当代解释

令任意固定整数为M,当M/A余a,M/B余b,M/C余c,M/D余d,…,M/Z余z时,这里的A,B,C,D,…,Z为除数,除数为任意自然数(如果为0,没有任何意义,如果为1,在孙子定理中没有计算和探讨的价值,所以,不包括0和1)时;余数a,b,c,d,z为自然整数时。
1、当命题正确时,在这些除数的最小公倍数内有解,有唯一的解,每一个最小公倍数内都有唯一的解;当命题错误时,在整个自然数范围内都无解。
2、当M在两个或两个以上的除数的最小公倍数内时,这两个或两个以上的除数和余数可以定位M在最小公倍数内的具体位置,也就是M的大小。
3、正确的命题,指没有矛盾的命题:分别除以A,B,C,D,…,Z不同的余数组合个数=A,B,C,D,…,Z的最小公倍数=不同的余数组合的循环周期.

问题分析

一、
"物不知数"问题的抽象表示:
x≡2(mod 3)
x≡3(mod 5)
x≡2(mod 7)

求满足上述条件的最小正整数x
二、
"物不知数"解法的数学表示:
任取被3除余2的5和7的倍数:140
任取被5除余3的7和3的倍数:63
任取被7除余2的3和5的倍数:30
140+63+30=233

减去3,5,7的公倍数中不超过233的最大的数210得到答案23

三、问题归化
一般性问题:给定两两互质的正整数n1,n2,...,nk,要求找到最小的正整数a,满足a≡ai(mod ni)
将问题分解成若干次求解二元模线性方程组的解

算法步骤

令n=n1n2···nk,mi=n/ni
利用扩展欧几里德算法计算出xi满足mixi ≡ 1(mod ni),由于n1,n2,...,nk两两互质,必有gcd(mi,ni)=1,即可保证一定有解
则a≡a1x1m1 + a2x2m2 + ... + akxkmk (mod n)


典型应用

大整数的表示
选取两两互素的正整数n1,n2,...,nk
已知对每个ni取模的值ri,就可以唯一确定一个1~n1n2...nk的大整数
做大整数加,减,乘法时,只要保证在这个范围内,均可转化为分别对相应的余数进行计算

模板代码

  1. <pre name="code" class="cpp">/*****  ACM之中国剩余定理 ********/  
  2.   
  3. /******** written by C_Shit_Hu ************/  
  4.   
  5. 扩展欧几里得算法的运用///  
  6.   
  7. /****************************************************************************/  
  8. /*  
  9. 由于VC下面无法使用cout或者cin输出64位的整数。 
  10. 故改用printf. 
  11. */  
  12. /****************************************************************************/  
  13.   
  14. #include<iostream>  
  15. using namespace std;  
  16. typedef _int64 llong;  
  17. llong b[1000],w[1000];  
  18.   
  19.   
  20. // 扩展欧几里得算法  
  21. // 递归的形式  
  22. llong extended_euclid(llong a, llong b, llong &x, llong  &y)   
  23. {  
  24.     llong d;  
  25.     if(b == 0)   
  26.     {x = 1; y = 0; return a;}  
  27.       
  28.     d = extended_euclid(b, a % b, y, x);  
  29.     y -= a / b * x;  
  30.     return d;  
  31. }  
  32.   
  33. // 中国剩余定理  
  34. llong chinese_remainder(int len)   
  35. {   
  36.     llong i, d, x, y, m, n, ret;  
  37.     ret = 0; n = 1;   
  38.     for(i=0; i < len ;i++) n *= w[i];  
  39.     for(i=0; i < len ;i++)   
  40.     {   
  41.         m = n / w[i];  
  42.         d = extended_euclid(w[i], m, x, y);  
  43.         ret = (ret + y*m*b[i]) % n;  
  44.     }  
  45.     return (n + ret%n) % n;  
  46. }  
  47.   
  48. int main()  
  49. {  
  50.     int  n,i;  
  51.     llong res;  
  52.     // 输入测试的除数和余数的组数  
  53.     cout << "输入测试的除数和余数的组数: " ;  
  54.     while (scanf("%d",&n)!=EOF)  
  55.     {  
  56.         // 输入除数和余数  
  57.         cout << "输入余数和除数:" << endl;  
  58.         for(i=0;i<n;i++)  scanf("%I64d%I64d",&b[i],&w[i]);  
  59.         res=chinese_remainder(n);  
  60.         cout << "结果为:" ;  
  61.         printf("%I64d\n",res);  
  62.         cout << "输入测试的除数和余数的组数: " ;  
  63.     }  
  64.     return 0;  
  65. }</pre><br><br>  
运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值