[lnsyoj163/luoguP1495]曹冲养猪
题意
求线性同余方程组
\[\begin{cases}x\equiv b_1\pmod{a_1}\\x\equiv b_2\pmod{a_2}\\\dots\\x\equiv b_n\pmod{a_n}\end{cases}
\]
的最小非负整数解,保证 \(a_1,a_2,\cdots,a_n\)互质。
sol
求解线性同余方程组,我们通常会选择中国剩余定理(CRT)来解决。
我们计算 \(A = a_1 \cdot a_2 \cdots a_n\),\(m_i = \frac{A}{a_i}\),由于 \(m_i\) 是除 \(a_i\) 外 \(a\) 中所有数的倍数,因此 \(k\cdot m_i \equiv 0 (\bmod a_p)(p\ne i)\),即该值只对第 \(i\) 个线性同余方程有影响。因此,我们只需要解线性同余方程\(m_i \cdot x \equiv 1\pmod{a_i}\),那么\(b_ix\)就是第\(i\)个线性同余方程的贡献,贡献的和即为线性同余方程组的一组合法解,将其取模\(A\)即可求出最小合法解
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 15;
int n;
int a[N], b[N];
LL exgcd(LL a, LL b, int &x, int &y){
if (!b){
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main(){
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i] >> b[i];
LL M = 1;
for (int i = 1; i <= n; i ++ ) M *= a[i];
LL sum = 0;
for (int i = 1; i <= n; i ++ ) {
int x, y;
LL d = exgcd(M / a[i], (LL) a[i], x, y);
int t = abs(a[i] / d);
x /= d;
sum += (x % t + t) % t * (M / a[i]) * b[i];
}
cout << sum % M << endl;
return 0;
}