[笔记] CRT & exCRT
[笔记] CRT & exCRT
构造法
求多组x≡ri(mod的解,d_i互质
余数(r_i = remainder),除数(d_i=divisor)
我们想啊,如果我们能找到一个数 k1\equiv1(mod\text{ }3)是 5 和 7 的倍数
一个数 k2\equiv1(mod\text{ }5) 是3和7的倍数
一个数 k3\equiv1(mod\text{ }7) 是3和5的倍数
那么这样的话我们的答案就是 k1*2+k2*3+k3*2
这样的话就是如何求这三个数了
首先我们求出 3,5,7 的 lcm=105
之后令
x1=105/3=35,x2=105/5=21,x3=105/7=15
我们可以得到三个线性同余方程
35a\equiv1(mod\text{ }3)
21b\equiv1(mod\text{ }5)
15c\equiv1(mod\text{ }7)
直接上扩欧就行了
所以 k1=35a=35*2=70
k2=21b=21∗1=21
k3=15c=15∗1=15
之后我们的答案就是
(k1∗2+k2∗3+k3∗2)\bmod lcm=23
曹冲养猪
板子from wzx(我的构造法过不了,不过有了扩欧也不想用这个方法了)
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define re register
#define maxn 25
using namespace std;
inline LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
LL r=exgcd(b,a%b,y,x);
y-=a/b*x;
return r;
}
inline LL read()
{
char c=getchar();
LL x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
LL a[maxn],b[maxn];
LL x,y;
int n;
LL lcm=1;
int main()
{
n=read();
for(re int i=1;i<=n;i++)
{
b[i]=read();
a[i]=read();
lcm*=b[i];
}
LL ans=0;
for(re int i=1;i<=n;i++)
{
LL xx=lcm/b[i];
LL r=exgcd(xx,b[i],x,y);
x=(x%b[i]+b[i])%b[i];
ans=(ans+x*xx*a[i]%lcm)%lcm;
}
cout<<ans<<endl;
return 0;
}
扩欧法
\begin{cases}
x &\equiv& r_1 \pmod{d_1}\\
x & \equiv& r_2 \pmod{d_2}\\
&\vdots\\
x & \equiv& r_n \pmod{d_n}
\end{cases}
此时如果d_1,d_2,\dots,d_n不互质怎么办?
观察两个同余式
- x\equiv r_1 \pmod{d_1}
- x\equiv r_2 \pmod{d_2}
可以化为
- x=k_1d_1 + r_1
- x=k_2d_2+r_2
因此
- k_2d_2+r_2=k_1d_1+r_1
- k_2d_2-k_1d_1=r_1-r_2
是不是有点像ax+bx=c
于是我们可以解出来
- k_2 ^{'} d_2+k_1 ^{'} d_1=gcd(d_1,d_2)
并乘上(r_1-r_2)/gcd(d_1,d_2)得到之前式子的解
- k_1=k_1 ^{'} \cdot (r_1-r_2)/gcd(d_1,d_2)
但是得gcd(d_1,d_2)|(r_1-r_2),不然是得不到通解的
因为是带着一个负号的,所以得到
- x_0= -k_1d_1+r_1
得到新方程x\equiv x_0 \pmod{ lcm(d_1,d_2)}
好的,开始,抠细节
- 首先,最后要取模lcm(d1,d2),快速乘的时候忘记了,挂掉x1
- 快速乘里面不能有负数,挂掉x2
- 快速乘也要取模lcm(d_1,d_2),挂掉x3
- lcm(d_1,d_2)应该这么写,d_1 /gcd(d_1,d_2)\cdot d_2,而不是d_1 \cdot d_2 / gcd(d_1,d_2),挂掉x4
- 把除号放里面,不然有逆元,(其实是因为模了一个不该模的东西)挂掉x5
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll n, x, y;
ll d[N], r[N];
ll mul(ll a, ll b, ll p){//龟速乘
int f = 1;
if(a < 0) f = -f, a = -a;
if(b < 0) f = -f, b = -b;
ll w = 0;
while(b){
if(b & 1)
w = (w + a) % p;
b >>= 1;
a = (a + a) % p;
}
return w * f;
}
ll exgcd(ll a, ll b){//扩欧
ll ans, t;
if(b == 0){
x = 1;
y = 0;
return a;
} else {
ans = exgcd(b, a % b);
t = x;
x = y;
y = t - a / b * y;
}
return ans;
}
ll exCRT(){
for(int i = 2; i <= n; ++i){
ll C = r[1] - r[i];
ll D = exgcd(d[i], d[1]);
if(C % D) return -1;
ll k1 = mul(y , c / D, d[1] / D * d[i] );
ll x0 = mul(-k1 , d[1], d[1] / D * d[i] ) + r[1];
d[1] = d[1] / D * d[i], r[1] = x0;
r[1] = (r[1] % d[1] + d[1]) % d[1];//先模一遍,让绝对值小于,然后处理
}
return r[1];
}
int main(){
scanf("%lld", &n);
for(int i = 1; i <= n; ++i){
scanf("%lld %lld", &d[i], &r[i]);
}
long long ans = exCRT();
printf("%lld", ans);
return 0;
}
我知道写的超级丑,比不上fym
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)