中国剩余定理
中国剩余定理
构造法(只适用模数两两互质的情况,CRT的本质思想)
-
对于解线性同余方程组 useless,因为完全可以被增量法代替
-
但是揭示了若模数两两互质,则线性同余方程组一定有解。
若模数为合数 ,
-
-
若给出一个模数不一定为质数线性方程组,判断是否有解,可将每个模数拆成 素数幂 的形式
对于底数相同的方程分到一组,可先假设幂最高的成立,这样就很容易检查幂低的是否矛盾,若有矛盾则无解
因为此时每一组之间的模数都是两两互质的,所以只要组中没有矛盾,则该方程组一定有解
-
中国剩余定理2 - 题目 - Daimayuan Online Judge
性质 2.2 的应用
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
//[p, [s, a]] 为该组以p为底,p的幂为s, x mod s = a
map<int, vector<PII> > mp;
bool solve()
{
int n;
scanf("%d", &n);
mp.clear();
while(n--)
{
int a, m;
scanf("%d%d", &a, &m);
for (int i = 2; i <= m / i; i++)
{
if (m % i)
continue;
int s = 1;
while(m % i == 0)
{
s *= i;
m /= i;
}
mp[i].push_back({s, a % s});
}
if (m > 1)
mp[m].push_back({m, a % m});
}
for (auto t : mp)
{
int p = t.first;
//找到该组幂最大的
int now = max_element(mp[p].begin(), mp[p].end())->second;
for (auto i : mp[p])
{
if (now == -1)
now = i.second;
if (now % i.first != i.second)
return false;
}
}
return true;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
if (solve())
puts("Yes");
else
puts("No");
}
return 0;
}
增量法 (适用于模数不一定两两互质的情况)
给定 个方程,求 ,满足 , 且
可逐一合并两个同余方程,最后剩下的同余方程 的 就是答案
合并两个同余方程的过程为:
中国剩余定理 - 题目 - Daimayuan Online Judge
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
ll xx, yy;
ll d = exgcd(b, a % b, xx, yy);
x = yy, y = xx - a / b * yy;
return d;
}
void merge(ll &a, ll &b, ll c, ll d) // d <= 1e9, b可能很大
{
// bt = c - a (mod d)
if (a == -1 && b == -1)
return;
ll x, y;
ll g = exgcd(b, d, x, y);
if ((c - a) % g != 0)
{
a = b = -1;
return;
}
d /= g; // d'
ll t0 = ((c - a) / g) % d * x % d; // 注意 c - a 可能很大,及时取模
//t = t0 (mod d')
if (t0 < 0) t0 += d; // 若为负数则 + 模数 就是最小非负整数
a = b * t0 + a;
b = b * d;
}
void solve()
{
int n;
scanf("%d", &n);
ll a = 0, b = 1; //当前的方程为 x mod b = a,每次迭代合并一个 x mod c = d
for (int i = 1; i <= n; i++)
{
ll c, d;
scanf("%lld%lld", &c, &d);
merge(a, b, c, d);
}
printf("%lld\n", a);
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
solve();
return 0;
}
并且中国剩余定理可以推出:
$
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】