为了复习某些数论……
经典求解同余方程,拓展Eculid是基础(需要求逆),除非想直接背程序的,都要先去看这个
网上证明比较多,我是之前看的NOI导刊上的
总结如下:(引用自qywyh,仅文字)
问题简单来说就是 a = ai (mod ni) 求未知数a,
以下小结略去证明, 只是对定理作了必要的解释, 要了解相关定理,可查阅数论资料.
中国余数定理:
设 n=n1*n2...nk, 其中因子两两互质.有: a-----(a1,a2,...,ak), 其中ai = a mod ni, 则 a和(a1,a2,...,ak)关系是一一对应的.就是说可以由 a求出(a1,a2,...,ak), 也可以由(a1,a2,...,ak)求出a
推论1:
对于 a=ai (mod ni) 的同余方程,有唯一解
下面说说由(a1, a2, ..., ak)求a的方法:
定义 mi = n1*n2*...nk / ni; ci = mi(mf mod ni); 其中 mi*mf mod ni = 1;
则 a = (a1*c1+a2*c2+...+ak*ck) (mod n) (注:由此等式可求a%n, 当n很大时)
中国剩余定理关键是mf的求法,如果理解了扩展欧几里得 ax+by=d, 就可以想到:
mi*mf mod ni = 1 => mi*mf+ni*y=1;
1 //?=1(mod ai) ai*x+1=? ai*x-?=1 by lcj2018 2 program sunzi; 3 var 4 i,n:integer; 5 x,y,m,ans,mi:longint; 6 a,c:array [1..1000] of integer; 7 procedure eculid(a,b:longint); 8 var 9 t:longint; 10 begin 11 if b=0 then begin 12 x:=1;y:=0;exit; 13 end; 14 eculid(b,a mod b); 15 t:=x;x:=y;y:=t-(a div b)*y; 16 end; 17 begin 18 readln(n); 19 for i:=1 to n do readln(a[i],c[i]); 20 m:=1;ans:=0; 21 for i:=1 to n do m:=m*a[i]; 22 for i:=1 to n do begin 23 x:=0;y:=0; 24 mi:=m div a[i]; 25 eculid(mi,a[i]); 26 ans:=(ans+c[i]*mi*(x mod a[i])) mod m; 27 end; 28 writeln(ans); 29 end.
下面来一道例题 poj1006 生理周期
- 生理周期
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 105785 | Accepted: 32777 |
Description
Input
当p = e = i = d = -1时,输入数据结束。
Output
采用以下格式:
Case 1: the next triple peak occurs in 1234 days.
注意:即使结果是1天,也使用复数形式“days”。
Sample Input
0 0 0 0 0 0 0 100 5 20 34 325 4 5 6 7 283 102 23 320 203 301 203 40 -1 -1 -1 -1
Sample Output
Case 1: the next triple peak occurs in 21252 days. Case 2: the next triple peak occurs in 21152 days. Case 3: the next triple peak occurs in 19575 days. Case 4: the next triple peak occurs in 16994 days. Case 5: the next triple peak occurs in 8910 days. Case 6: the next triple peak occurs in 10789 days.
题目不是很难,可以省略扩展Eculid求逆过程,手算
1 program p1006; 2 var 3 p,e,i,d,ans:integer; 4 t:longint; 5 begin 6 readln(p,e,i,d); 7 t:=0; 8 while (p<>-1) and (e<>-1) and (i<>-1) and (d<>-1) do begin 9 ans:=(p*5544+e*14421+i*1288) mod 21252-d;inc(t); 10 if ans<=0 then inc(ans,21252); 11 writeln('Case ',t,': the next triple peak occurs in ',ans,' days.'); 12 readln(p,e,i,d); 13 end; 14 end.