表达整数的奇怪方式AcWing 204 线性同余
题目传送门
首先看第一个同余方程,
x
≡
m
1
(
m
o
d
a
1
)
x\equiv m_1(mod \ a_1)
x≡m1(mod a1)可以化为
1
×
x
+
a
1
×
y
=
m
1
1\times x+a_1 \times y=m_1
1×x+a1×y=m1
可以根据扩展欧几里得算法求出一个
x
x
x的可行解,如果是负数
while (x < 0){
x = (x + a[1]) % a[1];
}
如果已经有了前k个同余方程的解为 x x x,前k+1个同余方程的解也可以求得
设 L C M k LCM_k LCMk是 l c m ( a 1 , a 2 , . . . , a k ) lcm(a_1,a_2,...,a_k) lcm(a1,a2,...,ak)
前k+1个同余方程的解设为 y y y,则一定满足 y = x + L C M k × n y=x+LCM_k\times n y=x+LCMk×n( n n n为整数),
同时 1 × y + a k + 1 × q = m k + 1 1\times y+a_{k+1}\times q=m_{k+1} 1×y+ak+1×q=mk+1
即 x + L C M k × n + a k + 1 × q = m k + 1 x+LCM_k\times n+a_{k+1}\times q=m_{k+1} x+LCMk×n+ak+1×q=mk+1
L C M k × n + a k + 1 × q = m k + 1 − x LCM_k\times n+a_{k+1}\times q=m_{k+1}-x LCMk×n+ak+1×q=mk+1−x
用扩展欧几里得算法检测是否有解,如果该方程无解,那么就不存在答案
若方程有解,则 y = x + L C M k × n y=x+LCM_k\times n y=x+LCMk×n
求解完第一个后,依据上述过程求解后续的解即可
求解过程中,如果扩展欧几里得算法求得了一个负数值,转变为正数,即与模数相加取模即可
最后程序会得到一个值,是一个满足条件的可行解,但是不一定最小,只需要对全部的数字的最小公倍数 L C M n LCM_n LCMn取模即可
假设最小可行解是 a n s ans ans,则通解是 a n s + L C M n × N ans+LCM_n\times N ans+LCMn×N( N N N为整数),通解对每一个 a i a_i ai取模时,可以分为两部分,第一部分取模后显然满足条件,而第二部分的 L C M n × N LCM_n\times N LCMn×N,因为 L C M n LCM_n LCMn是 a i a_i ai的倍数,因此取模后为0,所以最后结果依然满足条件,因此上述表达式为通解。
#include <bits/stdc++.h>
template <typename T>
void exgcd(T a, T b, T& x, T& y){
if (b == 0){
x = 1;
y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
template<typename T>
T gcd(T a, T b){
return b == 0 ? a : gcd(b, a % b);
}
template<typename T>
T lcm(T a, T b){
return a / gcd(a, b) * b;
}
long long a[30], m[30], n;
long long x, y, res, M;
int main(){
// freopen("in.in", "r", stdin);
// freopen("out.out", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin >> n;
for (int i = 1; i <= n; i++){
std::cin >> a[i] >> m[i];
}
M = a[1];
exgcd(1ll, a[1], res, y);
res = (res + a[1]) % a[1];
res *= m[1] / gcd(1ll, a[1]);
int i;
for (i = 2; i <= n; i++){
long long temp = m[i] - res;
while (temp < 0)temp = (temp + a[i]) % a[i];
temp %= a[i];
long long _gcd = gcd(M, a[i]);
if (temp % _gcd){
break;
}
exgcd(M, a[i], x, y);
x = (x + a[i]) % a[i];
x = (x * (temp / _gcd)) % a[i];
res += (x * M);
M = lcm(M, a[i]);
}
if (i <= n){
std::cout << "-1\n";
}
else std::cout << res % M << "\n";
return 0;
}
作者: correct
出处:https://www.cnblogs.com/correct/p/16548399.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现