【luogu P1495】【模板】中国剩余定理(CRT)/曹冲养猪(数论)

【模板】中国剩余定理(CRT)/曹冲养猪

题目链接:luogu P1495

题目大意

给你一些条件,要你找最小的 x,使得满足它被一些数取模的答案是要求的数。
且模数相互都是互质的。
在这里插入图片描述

思路

我们考虑我们先让每个式子单独找数满足,这个很好找,我们可以找到 x1,x2,...xn
那你考虑搞 x1+x2,看他能不能同时满足两个式子。
那你要想,那你为了不破坏余数,那你 x2 要是 a1 的倍数,x1 要是 a2 的倍数。

那你以此类推,变成所有的加起来,那就是要 x1a2,a3,...,an 的倍数,x2a1,a3,...,an 的倍数,.……。
这个很好找,就先搞出所有 a 的最小公倍数,然后除去 ai 就行。

那接着你 xi 还要满足模 aibi,那这一步要怎么处理呢?
那你要求 LCM×mbi(mod ai)
不如先求 LCM×m1(mod ai),然后再拿结果乘 bi
然后不难看出 m 就是 LCM 关于 ai 的逆元。

那你就求得了 x1,x2,...,xn
加起来就是一个解了。

但是我们要求最小解,那我们考虑通解。
那模 ai 的余数什么时候回循环一次呢?(完全匹配的那种)
不难想到是 lcm{ai} 个循环一次。
那就把答案模 LCM 就可以了。

代码

#include<cstdio> #define ll long long using namespace std; int n; ll a[11], b[11], LCM, X; ll gcd(ll x, ll y) { if (!y) return x; return gcd(y, x % y); } ll exgcd(ll a, ll b, ll &x, ll &y) {//exgcd 求逆元 if (!b) { x = 1; y = 0; return a; } ll re = exgcd(b, a % b, y, x); y -= x * (a / b); return re; } int main() { scanf("%d", &n); LCM = 1; for (int i = 1; i <= n; i++) { scanf("%lld %lld", &a[i], &b[i]); LCM = LCM * a[i] / gcd(LCM, a[i]);//求积 } for (int i = 1; i <= n; i++) { ll mi = LCM / a[i]; ll x = 0, y = 0; exgcd(mi, a[i], x, y); X += b[i] * mi * ((x % a[i] + a[i]) % a[i]);//注意 x 有可能是负数 } printf("%lld", X % LCM); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P1495.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(148)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示