中国剩余定理(扩展)
算法简介
中国剩余定理(Chinese Remainder Theorem,CRT)可以用来求解如下形式的一元线性同余方程组。(注意,两两互质)
基本思路
如果可以找到k个x满足:
那么显然将这k个x加起来就能得到一个满足要求的解。
进一步来看。,这个条件很好满足,只需要令 即可,记这个值为 ,为了满足 ,直接令 ,然而 ,还不能满足要求,再乘以一个逆元就行啦。
算法流程
1.计算所有模数的积。
2.对于每个:
a.计算。
b.计算。
3.方程组的解为。
例题
P1495 【模板】中国剩余定理(CRT)/曹冲养猪
参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n;
ll a[20];
ll N=1;
ll exgcd(ll a,ll b,ll&x,ll &y){
if(b==0){
x=1;
y=0;
return a;
}
ll temp;
ll d=exgcd(b,a%b,x,y);
temp=x;
x=y;
y=temp-a/b*y;
return d;
}
ll ans=0;
ll b[20];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%lld%lld",&a[i],&b[i]);
N*=a[i];
}
for(int i=1;i<=n;++i){
ll x,y;
ll d=exgcd(N/a[i],a[i],x,y);
x=(x%a[i]+a[i])%a[i];//注意exgcd求解得到的逆元可能是负的
ans+=b[i]*N/a[i]*x;
ans%=N;
}
printf("%lld",ans);
return 0;
}
扩展
对于刚刚的问题,若模数不严格两两互质,就无法用扩展欧几里得求乘法逆元,所以要使用新的算法。
基本思路
假设我们已经求出前个方程组的一个解,并且有(及N是前k-1个数的最小公倍数)。
则前k-1个方程的通解为。
那么对于第k个方程,要找到一个合适的i使。
其实就是求解,这个时候就又可以用扩展欧几里得求解了。然后再一直往下合并即可。
例题
P4777 【模板】扩展中国剩余定理(EXCRT)
参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10;
ll ai[N],bi[N];
int n;
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;
y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
ll temp=x;
x=y;
y=temp-a/b*y;
return d;
}
ll mul(ll a,ll b,ll mod){
ll ans=0;
while(b){
if(b&1)ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
ll excrt(){
ll M=ai[1],ans=bi[1];
for(int i=2;i<=n;++i){
ll x,y,a=M,b=ai[i];
ll c=(bi[i]-ans%b+b)%b;
ll d=exgcd(a,b,x,y);
c=mul(x,c/d,ai[i]/d);
ans+=c*M;
M*=ai[i]/d;
ans=(ans%M+M)%M;
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lld%lld",&ai[i],&bi[i]);
printf("%lld",excrt());
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现