中国剩余定理来源及推导:https://www.cnblogs.com/MashiroSky/p/5918158.html
中国剩余定理(CRT)表述及模板:https://blog.csdn.net/acdreamers/article/details/8050018
中国剩余定理——求解一次同余式组 x ≡ a i ( m o d m i ) x\equiv a_i(mod\ m_i) x≡ai(mod mi)的方法:
注:要求所有的模数 m i m_i mi互质
int CRT(int* a,int* m,int n)//余数、模数、同余式组个数
{
int ans=0,M=1;//M为所有模数的乘积
for(int i=1;i<=3;i++)M*=m[i];
for(int i=1;i<=n;i++)
{
int x,y;
int Mi=M/m[i];
//Mi*x=1(mod m[i])
//Mi*x+m[i]*y=1
exgcd(Mi,m[i],x,y);//求Mi关于m[i]的逆元x
(ans+=a[i]*Mi*x)%=M;
}
if(ans<0)ans+=M;
return ans;
}
题目:http://poj.org/problem?id=1006
#include
#include
#include
#include
using namespace std;
const int manx=2e3;
int m[manx],a[manx];
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int gcd=exgcd(b,a%b,x,y);
int temp=x;
x=y;
y=temp-(a/b)*y;
return gcd;
}
int CRT(int* a,int* m,int n)
{
int ans=0,M=1;
for(int i=1;i<=3;i++)M*=m[i];
for(int i=1;i<=n;i++)
{
int x,y;
int Mi=M/m[i];
exgcd(Mi,m[i],x,y);
(ans+=a[i]*Mi*x)%=M;
}
if(ans<0)ans+=M;
return ans;
}
int main()
{
int p,e,i,d,cou=1,M;
while(scanf("%d%d%d%d",&p,&e,&i,&d)!=EOF)
{
if(p==-1&&e==-1&&i==-1&&d==-1)
break;
a[1]=p%23;
a[2]=e%28;
a[3]=i%33;
m[1]=23;
m[2]=28;
m[3]=33;
int ans=CRT(a,m,3,M);
if(d>=ans)
ans+=21252;
printf("Case %d: the next triple peak occurs in %d days.\n",cou++,ans-d);
}
return 0;
}
中国剩余定理扩展——求解模数不互质情况下的线性方程组:
将 x ≡ a i ( m o d m i ) x\equiv a_i(mod\ m_i) x≡ai(mod mi)
转化一下:
x = a 1 + m 1 x 1 x=a_1+m_1x_1 x=a1+m1x1
x = a 2 + m 2 x 2 x=a_2+m_2x_2 x=a2+m2x2( x = a 2 − m 2 x 2 x=a_2-m_2x_2 x=a2−m2x2)
两两合并。左边相等,通过扩欧求出 x 1 x_1 x1(或 x 2 x_2 x2)的最小整数解,然后带回得到 x x x的最小整数解 x ′ x' x′,即得 x x x的通解 x = x ′ + k ∗ l c m ( m 1 , m 2 ) x=x'+k*lcm(m_1,m_2) x=x′+k∗lcm(m1,m2)。
即 x ≡ x ′ ( m o d l c m ( m 1 , m 2 ) ) x\equiv x'(mod\ lcm(m_1,m_2)) x≡x′(mod lcm(m1,m2))
#include
typedef long long LL;
const int manx=2e3;
LL m[manx],a[manx];
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
LL gcd=exgcd(b,a%b,x,y);
LL temp=x;
x=y;
y=temp-(a/b)*y;
//LL gcd=exgcd(b,a%b,y,x);
//y-=(a/b)*x;
return gcd;
}
LL ex_CRT(LL* a,LL* m,LL n)//余数、模数、同余式组个数
{
for(int i=2; i<=n; i++)
{
LL x,y,c=a[i]-a[i-1];
//x=a1+m1x1=a2-m2x2
//m1x1+m2x2=a2-a1=c
LL gcd=exgcd(m[i-1],m[i],x,y);
if(c%gcd)
return -1;
x=x*c/gcd;
LL temp=m[i]/gcd;
x=(x%temp+temp)%temp;//求x1的最小正整数解
a[i]=a[i-1]+x*m[i-1],m[i]=m[i]*m[i-1]/gcd;
}
return a[n];
}
int main()
{
LL k,a[manx],r[manx];
while(~scanf("%I64d",&k))
{
for(int i=1; i<=k; i++)
scanf("%I64d%I64d",&a[i],&r[i]);
LL ans=ex_CRT(r,a,k);
printf("%I64d\n",ans);
}
return 0;
}