专栏文章
速通中国剩余定理
算法·理论参与者 3已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @mk74k8e4
- 此快照首次捕获于
- 2026/01/10 01:03 上个月
- 此快照最后确认于
- 2026/02/19 01:19 17 小时前
反正是复习,我长话短说只写这玩意重点了.
CRT
题目
给定 组非负整数 ,求解关于 的方程组的最小非负整数解。
对于 的数据,,,,保证所有 的最小公倍数不超过 ,保证 中的元素两两互质。
数据保证有解。
思路
设 。
我们对于每个 ,算出这样的一个 满足:
可以用括欧做出来,然后答案就是:
原理大概就是当前方程的满足模其他几个方程都是 ,我们算出模当前模数为 的结果后就满足了当前的方程,最后一个一个加起来就全满足了。
代码
原题曹冲养猪会爆ll,所以代码里开了__int128
CPP#include<bits/stdc++.h>
using namespace std;
#define int __int128
int gcd(int x, int y)
{
return y == 0 ? x : gcd(y, x % y);
}
int lcm(int x, int y)
{
return x / gcd(x, y) * y;
}
void exgcd(int a, int b, int &x, int &y)
{
if (b == 0) {
x = 1;
y = 0;
return;
}
exgcd(b, a % b, x, y);
int tp = x;
x = y;
y = tp - (a / b) * y;
}
pair<int, int> solveeqn(int a, int b, int k)
{
if (k % gcd(a, b)) {
return {-1, -1};
}
int x0, y0;
exgcd(a, b, x0, y0);
int g = gcd(a, b);
int tp = k / g;
x0 *= tp;
y0 *= tp;
while (x0 < 0) {
x0 += b / g;
y0 -= a / g;
}
return {x0, y0};
}
signed main()
{
long long n;
cin >> n;
vector<long long> a(n), m(n);
int s = 1;
for (int i = 0; i < n; i++) {
cin >> m[i] >> a[i];
s *= m[i];
}
int ans = 0;
for (int i = 0; i < n; i++) {
int tp = solveeqn(s / m[i], m[i], 1).first;
if (tp == -1) {
cout << -1 << '\n';
return;
}
ans += a[i] * s / m[i] * tp;
}
ans %= s;
if (ans < 0) {
ans += s;
}
cout << (long long)ans << '\n';
return 0;
}
EXCRT
题目
给定 组非负整数 ,求解关于 的方程组的最小非负整数解。
对于 的数据,,,,保证所有 的最小公倍数不超过 。
数据保证有解。
思路
现在里面的数不两两互质了,所以上面的方法是行不通的。
我们先考虑只有两个同余方程的情况:
这里 就能表示成 的形式,也可以表示成 的形式。
所以我们就能得到关于 的一个不定方程:
扩展欧几里得就可以把 和 这两个未知数解出来。
那么很容易就能把这两个方程合并为一个方程:
然后一直合并下去就做完了,喵。
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
void exgcd(__int128 a, __int128 b, __int128 &x, __int128 &y) // ax+by=gcd(a,b)的解
{
if (b == 0) {
x = 1;
y = 0;
return;
}
exgcd(b, a % b, x, y);
__int128 tp = x;
x = y;
y = tp - (a / b) * y;
}
__int128 gcd(__int128 x, __int128 y)
{
return y == 0 ? x : gcd(y, x % y);
}
__int128 lcm(__int128 x, __int128 y)
{
return x / gcd(x, y) * y;
}
pair<__int128, __int128> solveeqn(__int128 a, __int128 b, __int128 k)
{
if (k % gcd(a, b)) {
return {-1, -1};
}
__int128 x0, y0;
exgcd(a, b, x0, y0);
__int128 g = gcd(a, b);
__int128 tp = k / g;
x0 *= tp;
y0 *= tp;
if (x0 < 0) {
int tp = (0 - x0 + b / g - 1) / (b / g);
x0 += tp * (b / g);
y0 -= tp * (b / g);
}
return {x0, y0};
}
signed main()
{
int n;
cin >> n;
vector<int> a(n), m(n);
for (__int128 i = 0; i < n; i++) {
cin >> m[i] >> a[i];
}
__int128 tpa = a[0], tpm = m[0];
for (__int128 i = 1; i < n; i++) {
auto tp = solveeqn(tpm, -m[i], tpa - a[i]);
tpa -= tpm * tp.first;
tpm = lcm(tpm, (__int128)m[i]);
tpa = (tpa + tpm) % tpm;
if (tpa < 0) {
tpa += tpm;
}
}
cout << (int)tpa;
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...