前言:
中国剩余定理又名孙子定理。因孙子二字歧义,常以段子形式广泛流传。
中国剩余定理并不是很好理解,我也理解了很多次。
CRT 中国剩余定理
中国剩余定理,就是一个解同余方程组的算法。
求满足n个条件的最小的x。
看起来很麻烦。
先找一个特殊情况:$m_1,m_2,...m_n$两两互质。
这个时候,构造$M=m_1*m_2*...m_n$;
令$M_i=M/m_i$;
所以,构造$n$个数,其中第$i$个数是除$i$之外的其他所有数的倍数,并且第$i$个数$mod m_i =1$
即:$M_i x = 1 ( mod m_i ) $求出这样一个x,就求出了 这个数。
因为$m$之间两两互质,所以对于$n$个这样的方程,$x$本质上就是$M_i$在$m_i$意义下的乘法逆元。
(不会$exgcd$?左转:EXGCD 扩展欧几里得)
因为互质,一定有解的。
用扩展欧几里得算就可以。
同理,构造$n$个数。$b_1,b_2....b_n$
其中,$b_i=M_i \times x_i$
那么,因为$b_i = 1 (mod m_i)$,所以$ b_i * a_i = a_i (mod m_i)$
那么,原题目中的这个x就是:$x=(a_1\times b_1+a_2\times b_2+...+a_n\times b_n) $验证一下,是不是?
总得来说,
对于$mi$互质的情况,$x=\sum_1^n M_i\times a_i\times inv_i$
其中,$inv_i$表示,$M_i$在$mod\space m_i$意义下的逆元。
当然,为了保证$x$最小,要让$x$和$lcm$做一些处理。当然,因为互质,所以$lcm$就是$M$了
x=(x%M+M)%M
例题:poj1006 生理周期 Biorhythms
在CRT上的小小变形。注意开始计算的时间d就好了。上述最小的$x$就是$n+d$
答案$n=(a_1\times b_1+a_2\times b_2+a_3\times b_3-d)%lcm$
#include<cstdio> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; int p,e,l; int p1,e1,l1; int tt,d; void exgcd(int a,int b,int &x,int &y){ if(b==0){ x=1,y=0;return; } exgcd(b,a%b,y,x); y-=(a/b)*x; } int main(){ exgcd(23*28,33,l1,tt); l1=(l1%33+33)%33; l1*=23*28; exgcd(28*33,23,p1,tt); p1=(p1%23+23)%23; p1*=28*33; exgcd(23*33,28,e1,tt); e1=(e1%28+28)%28; e1*=23*33; int lcm=23*28*33; int cnt=0; while(1){ ++cnt; scanf("%d%d%d%d",&p,&e,&l,&d); if(p==-1) break; int op=(p1*p+e1*e+l1*l-d+lcm)%lcm; if(op==0) op=lcm; printf("Case %d: the next triple peak occurs in %d days.\n",cnt,op); } return 0; }