中国剩余定理(CRT)

CRT

中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组

{xr1 (mod p1)xr2 (mod p2)...xrn (mod pn)

其中 p1,p2...pn两两互质

结论

1 . 计算所有模数的积 n

2 . 对于第 i 个方程:

  • 计算 mi=nni
  • 计算 mi 在模 ni 意义下的逆元 mi1
  • 计算 ci=mimi1(不要对 ni 取模)。

3 . 方程组在模 n 意义下的唯一解为:x=i=1kaici(modn)

il int crt(int a[],int n[],int k){
    int x=0,N=1;
    for(ri int i=1;i<=k;++i) N*=n[i];
    for(ri int i=1,m,inv,y;i<=k;++i){
        m=N/n[i];
        exgcd(m,n[i],inv,y);
        inv=(inv%n[i]+n[i])%n[i];
        x=(x+a[i]*m*inv%N)%N;
    }
    return (x%N+N)%N;
}
code
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
#define int __int128
using namespace std;
cs int MAXN=15;
il int rd(){
    ri int x=0,f=1;
    ri char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') f=-f;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+(c^48),c=getchar();
    return x*f;
}
il void wt(int x){
    if(x<0) x=-x,putchar('-');
    if(x>9) wt(x/10);
    return putchar(x%10+48),void();
}
il void exgcd(cs int a,cs int b,int &x,int &y){
    if(!b) return x=1,y=0,void();
    exgcd(b,a%b,y,x);
    return y-=x*(a/b),void();
}
il int crt(int a[],int n[],int k){
    int x=0,N=1;
    for(ri int i=1;i<=k;++i) N*=n[i];
    for(ri int i=1,m,inv,y;i<=k;++i){
        m=N/n[i];
        exgcd(m,n[i],inv,y);
        inv=(inv%n[i]+n[i])%n[i];
        x=(x+a[i]*m*inv%N)%N;
    }
    return (x%N+N)%N;
}
signed main(){
    int n=0,a[MAXN]={0},b[MAXN]={0};
    n=rd();
    for(ri int i=1;i<=n;i++){
        a[i]=rd(),b[i]=rd();
    }
    int ans=crt(b,a,n);
    wt(ans);
    return 0;
}

exCRT

对于p1,p2...pn不一定互质的情况就需要用到 exCRT

结论

两个方程

1 . 设两个方程分别是 xa1(modm1)xa2(modm2)
2 . 将它们转化为不定方程:x=m1p+a1=m2q+a2 ,其中 p,q 是整数,则有 m1pm2q=a2a1
3 . 由裴蜀定理,当 a2a1 不能被 gcd(m1,m2) 整除时,无解;
4 . 其他情况下,可以通过扩展欧几里得算法解出来一组可行解 (p,q)
5 . 则原来的两方程组成的模方程组的解为 xb(modM),其中 b=m1p+a1M=lcm(m1,m2)

多个方程

用上面的方法两两合并即可。

il int excrt(int a[],int b[],int n){
    int a1=a[1],b1=b[1];
    for(ri int i=2,x,y;i<=n;++i){
        exgcd(b1,b[i],x,y);
        if((a[i]-a1)%gcd){printf("No solution");return 0;}
        x=((x*((a[i]-a1)/gcd))%(b[i]/gcd)+(b[i]/gcd))%(b[i]/gcd);
        a1=(a1+x*b1)%(b1*b[i]/gcd),b1*=b[i]/gcd;
    }
    return a1;
}
code
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
#define F(s) freopen(#s".in","r",stdin),freopen(#s".out","w",stdout); 
#define int __int128
using namespace std;
il int rd(){
    ri int x=0;
    ri char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+(c^48),c=getchar();
    return x;
}
il void wt(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) wt(x/10);
    return putchar(x%10+48),void();
}
int gcd;
il void exgcd(cs int a,cs int b,int &x,int &y){
    if(!b) return x=1,y=0,gcd=a,void();
    return exgcd(b,a%b,y,x),y-=a/b*x,void();
}
il int excrt(int a[],int b[],int n){
    int a1=a[1],b1=b[1];
    for(ri int i=2,x,y;i<=n;++i){
        exgcd(b1,b[i],x,y);
        if((a[i]-a1)%gcd){printf("No solution");return 0;}
        x=((x*((a[i]-a1)/gcd))%(b[i]/gcd)+(b[i]/gcd))%(b[i]/gcd);
        a1=(a1+x*b1)%(b1*b[i]/gcd),b1*=b[i]/gcd;
    }
    return a1;
}
cs int N=1e5+5;
int n,a[N],b[N];
signed main(){
    n=rd();
    for(ri int i=1;i<=n;++i) a[i]=rd(),b[i]=rd();
    wt(excrt(b,a,n));
    return 0;
}

edit

posted @   雨夜风月  阅读(141)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示