中国剩余定理的具体描述是这样的:
给出你n个ai和mi,最后让求出x的最小值是多少。
中国剩余定理说明:假设整数m1, m2, ... , mn两两互质,则对任意的整数:a1, a2, ... , an,方程组有解,并且通解可以用如下方式构造得到:
- 设是整数m1, m2, ... , mn的乘积,并设是除了mi以外的n - 1个整数的乘积。
- 设为模的数论倒数:
- 方程组的通解形式为: 在模的意义下,方程组只有一个解:
分割线
下面我们来看一个具体的例子:
使用中国剩余定理来求解上面的“物不知数”问题,便可以理解《孙子歌诀》中的数字含义。这里的线性同余方程组是:
三个模数m13, m25, m37的乘积是M105,对应的M135, M221, M315. 而可以计算出相应的数论倒数:t12, t21, t31. 所以《孙子歌诀》中的70,21和15其实是这个“物不知数”问题的基础解:
而将原方程组中的余数相应地乘到这三个基础解上,再加起来,其和就是原方程组的解:
这个和是233,实际上原方程组的通解公式为:
《孙子算经》中实际上给出了最小正整数解,也就是k-2时的解:x23.
附:数论倒数 wiki具体代码参考如下:(应该很明了)
-
///n个mi互质
-
const LL maxn = 20;
-
LL a[maxn], m[maxn], n;
-
LL CRT(LL a[], LL m[], LL n)
-
{
-
LL M = 1;
-
for (int i = 0; i < n; i++) M *= m[i];
-
LL ret = 0;
-
for (int i = 0; i < n; i++)
-
{
-
LL x, y;
-
LL tm = M / m[i];
-
ex_gcd(tm, m[i], x, y);
-
ret = (ret + tm * x * a[i]) % M;
-
}
-
return (ret + M) % M;
-
}
分割线
下面也就是关于这个的扩展,前面我们已经说了,中国剩余数定理是适用于n个mi两两互质的情况的,如果不互质呢,下面就是一个转换:
-
///n个mi不互质
-
const LL maxn = 1000;
-
LL a[maxn], m[maxn], n;
-
LL CRT(LL a[], LL m[], LL n) {
-
if (n == 1) {
-
if (m[0] > a[0]) return a[0];
-
else return -1;
-
}
-
LL x, y, d;
-
for (int i = 1; i < n; i++) {
-
if (m[i] <= a[i]) return -1;
-
d = ex_gcd(m[0], m[i], x, y);
-
if ((a[i] - a[0]) % d != 0) return -1; //不能整除则无解
-
LL t = m[i] / d;
-
x = ((a[i] - a[0]) / d * x % t + t) % t; //第0个与第i个模线性方程的特解
-
a[0] = x * m[0] + a[0];
-
m[0] = m[0] * m[i] / d;
-
a[0] = (a[0] % m[0] + m[0]) % m[0];
-
}
-
return a[0];
-
}
以上大部分内容来自wiki
下面做几道练手的题目:
poj2891,n个mi不互质的裸题
poj1006,三个互质的裸题