中国剩余定理
中国剩余定理
构造法(只适用模数两两互质的情况,CRT的本质思想)
-
对于解线性同余方程组 useless,因为完全可以被增量法代替
-
但是揭示了若模数两两互质,则线性同余方程组一定有解。
若模数为合数 \(q\), \(q=p_1^{e_1}*p_2^{e_2}*p_3^{e_3}*...p_k^{e_k}\)
-
\(x\mod q = a\iff x \mod p_i^{e_i}=a \;同时成立\)
-
若给出一个模数不一定为质数线性方程组,判断是否有解,可将每个模数拆成 素数幂 的形式
对于底数相同的方程分到一组,可先假设幂最高的成立,这样就很容易检查幂低的是否矛盾,若有矛盾则无解
因为此时每一组之间的模数都是两两互质的,所以只要组中没有矛盾,则该方程组一定有解
-
中国剩余定理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;
}
增量法 (适用于模数不一定两两互质的情况)
给定 \(n\) 个方程,求 \(x\) ,满足 \(x\equiv a_i\;(mod \;m_i)\), 且 \(0<=x<lcm(m_1,m_2...m_n)\)
可逐一合并两个同余方程,最后剩下的同余方程 \(x \equiv a \;(mod \;lcm(m_1,m_2...m_n))\) 的 \(a\) 就是答案
合并两个同余方程的过程为:
\[\begin{aligned}
&1.\\
&x\equiv a\;(mod\;b)\\
&x\equiv c\;(mod\;d)\\
&x=b*t+a,\;所以解出\;t\;即可\\
&带入第二个同余方程得:b*t\equiv c-a\;(mod\;d)\\
&令\;g=exgcd(b,d)\\
&若\;g\nmid c-a,\; 则\;该同余方程组无解\\
&2.\\
&否则在\;g=exgcd(b,d)\;中解得的\;t_0\;为\;b*t+d*s=g\;的一个\;t\;的解\\
&令\;d'=\frac dg\;则通解\;t=t_0+d'*y\;(y\;为常数)\\
&此时找到最小的一个非负整数解\;t_0,即若\;t_0<0\;则\;t_0=t_0+d'\\
&3.\\
&令\;t_0=t_0*\frac {c-a}g,\;此时\;t_0\;为\;b*t+d*s=c-a\;的一个解\\
&即\;t_0\;为\;b*t\equiv c-a\;(mod\;d)\;的解\\
&通解仍为\;t=t_0+d'*y\;(y\;为常数)\\
&4.\\
&x=b*t+a=b*(t_0+d'*y)+a=b*d'*y+b*t_0+a\\
&因此\;x\equiv b*t_0+a\;(mod\;b*d')
\end{aligned}
\]
中国剩余定理 - 题目 - 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;
}
并且中国剩余定理可以推出:
\(q=p_1^{e_1}*p_2^{e_2}*p_3^{e_3}*...p_k^{e_k}\)
$