晚上好🌙🌙🌙
本答案参考通义千问
这段代码是用于求解中国剩余定理(CRT)的模板,但确实存在一个错误,导致在某些情况下无法正确输出结果。下面我将详细分析问题,并给出解决方案。
🚨 问题分析
1. 函数 e 的定义不正确
你定义了一个函数 e,它应该是一个扩展欧几里得算法的实现,用于求两个数的最大公约数以及贝祖等式中的系数 x 和 y,即:
$$
\text{gcd}(a, b) = ax + by
$$
然而,在你的函数中,参数顺序是:
e(l a, l b, l &x, l &y),而实际上应该是:
l e(l a, l b, l &x, l &y)
这在 C++ 中是允许的,但更常见的写法是 e(l a, l b, l &x, l &y),所以这部分没有语法错误。
2. 关键错误:Mi * x % M 的计算方式不正确
在 CRT 中,我们需要计算:
$$
M_i \cdot x_i \mod m_i = 1
$$
其中 $ x_i $ 是 $ M_i^{-1} \mod m_i $,也就是 $ M_i $ 在模 $ m_i $ 下的逆元。
但是在你的代码中,你用了:
t = (t + a[i] * Mi % M * x) % M;
这里的问题在于:Mi % M 是不必要的,因为 Mi = M / m[i],而 M 是所有模数的乘积,所以 Mi 是 m[i] 的倍数吗?不是!Mi 是其他模数的乘积,所以 Mi 可能比 M 小,因此 Mi % M 等于 Mi。
但是,更重要的是,你在计算 Mi * x 时,没有考虑模的意义,正确的做法是计算 Mi * x % m[i],而不是 Mi * x % M!
✅ 正确的中国剩余定理实现逻辑
中国剩余定理的步骤如下:
- 计算所有模数的乘积 $ M = m_1 \times m_2 \times \cdots \times m_n $
- 对于每个 $ i $:
- 计算 $ M_i = M / m_i $
- 找到 $ x_i $,使得 $ M_i \cdot x_i \equiv 1 \mod m_i $ (即 $ x_i = M_i^{-1} \mod m_i $)
- 累加 $ t = (t + a_i \cdot M_i \cdot x_i) \mod M $
🔧 修改后的代码
下面是修正后的版本,解决了上述问题:
#include <bits/stdc++.h>
using namespace std;
typedef long long l;
const int N = 15;
int m[N], a[N];
// 扩展欧几里得算法
l e(l a, l b, l &x, l &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
l d = e(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main() {
int n;
cin >> n;
l M = 1;
for (int i = 1; i <= n; i++) {
cin >> m[i] >> a[i];
M *= m[i];
}
l t = 0;
for (int i = 1; i <= n; i++) {
l Mi = M / m[i];
l x, y;
l g = e(Mi, m[i], x, y); // 求 Mi 和 m[i] 的 gcd 及 x, y
// 确保 Mi 和 m[i] 互质,否则无解
if (g != 1) {
cout << "无解" << endl;
return 0;
}
// 计算 Mi 的逆元
l inv_Mi = (x % m[i] + m[i]) % m[i]; // 确保为正数
t = (t + a[i] * Mi * inv_Mi) % M;
}
t = (t + M) % M; // 避免负数
cout << t << endl;
return 0;
}
⚠️ 注意事项
- 必须保证所有模数 $ m_i $ 两两互质,否则 CRT 不适用。
- 如果模数不互质,需要使用扩展中国剩余定理(EXCRT)。
- 在代码中加入判断
if (g != 1) 是为了处理非互质情况,避免错误。
✅ 总结
| 问题 | 解决方案 |
|------|----------|
| Mi * x % M 错误 | 改为 Mi * x % m[i],即计算逆元 |
| 没有处理非互质情况 | 添加 if (g != 1) 判断 |
| 负数处理 | t = (t + M) % M |
如果你提供具体的样例输入和输出,我可以进一步验证修改后的代码是否通过。