中国剩余定理
[zz]中国剩余定理
转载自:http://tuzkier.kilu.de/blog/?p=29
下面讲讲中国剩余定理:
我国有一本数学古书「孙子算经」有这样一道问题:「今有物,不知其数,三三数之,剩二;五五数之,剩三;七七数之,剩二。问物几何?」
此题的意思是:有一批物品,三个三个地数,剩两个;五个五个地数,剩三个;七个七个地数,剩两个。问这批物品至少有多少个?
明代数学家程大位在其<算法统宗>里用口诀“:三人同行七十稀,五树梅花廿一,七子团圆月正半,除百零五便得知.”表达的。
这个口诀的意思是:把用3除所得的余数乘以70,加上用5除所得的余数乘以21,再加上用7除所得的余数乘以15,结果若是比105大,就减去105的倍数,便得所求的数。
这就是被称之为“中国剩余定理”。
根据上面所说的 举个例子:
一般题目的形式都是: 已知n1、n2、n3是两两互质的正整数,求最小正整数x,使它被n1、n2、n3除所得余数分别为r1、r2、r3
.”
若 n1 = 3,n2 = 5, n3 = 7,r1 = 2,r2 = 3, r3 = 2. 求x
M1 = 70 = 3*23+1 = 5*7*2
M2 = 21 = 5*4+1 = 3*7*1
M3 = 15 = 2*7 + 1 = 3*5*1
而 70 21
15 从何而来?
70 是 n2跟n3的公倍数 而且对n1取余为1
21 是 n1跟n3的公倍数 而且对n2取余为1
15 是 n1跟n2的公倍数 而且对n3取余为1
依次类推 如果个数为m的话 nm(m为下标)就是n1,n2…….n(m-1)的公倍数 且对nm取余为1
于是得到 ans = M1+M2+M3 = 233
再来看这道题(指的是HDOJ 1370 http://acm.hdu.edu.cn/showproblem.php?pid=1370)
读入p,e,i,d 4个整数,(n+d)%23=p; (n+d)%28=e; (n+d)%33=i ,求n
。
怎么求?这就要谢谢韩信了!
韩信是汉高祖刘邦手下的大将,他英勇善战,智谋超群,为汉朝的建立了卓绝的功劳。据说韩信的数学水平也非常高超,他在点兵的时候,为了保住军事机密,不让
敌人知道自己部队的实力,先令士兵从1至3报数,然后记下最后一个士兵所报之数;再令士兵从1至5报数,也记下最后一个士兵所报之数;最后令士兵从1至7
报数,又记下最后一个士兵所报之数;这样,他很快就算出了自己部队士兵的总人数,而敌人则始终无法弄清他的部队究竟有多少名士兵。
这个故事中所说的韩信点兵的计算方法就是“中国剩余定理”
n1 = 23
n2 = 28 n3 = 33
可得 (28*33)*K
%23 == 1 ,(23*33)*K%28 == 1 (23*28)*K%33 == 1
得到 M1 = 5544 M2 = 14421 M3 =
1288
这一步可以预处理掉
或者自己算出来 然后直接复制 相对高效了!!!
然后:
(5544×p+14421×e+1288×i)%(23×28×33)=n+d
n=(5544×p+14421×e+1288×i-d)%(23×28×33)
这样就可以得到结果了!不过有些情况还要再处理下 比如n==0
其实n 是23*28*33 = 21252
还有小于0 的情况 这些就要经过(n + 21252 -
1)%21252 + 1的处理了!!!
结果出来了 中国剩余定理也理解了!最后贴上我的代码:
#include
int main ()
{
int ans,Cass
= 0,pl,el,il,pass;
int R1 =
5544,R2 = 14421,R3 = 1288,R = 21252; // 为了效率 直接赋值了!可以预处理计算!
while(scanf(“%d %d %d
%d”,&pl,&el,&il,&pass)
&&(pl != -1 || el != -1 || il != -1
|| pass != -1))
{
Cass
++;
ans = (pl*R1
+ el*R2 + il*R3 – pass)%R; // 大部分已经可以算出结果了!!!
ans = (ans +
R – 1)%R + 1; //处理ans小于等于0的情况
printf(“Case
%d: the next triple peak occurs in %d days.\n”,Cass,ans);
}
return
0;
}

浙公网安备 33010602011771号