中国剩余定理

线性同余方程
https://en.wikipedia.org/wiki/Chinese_remainder_theorem

任何情况下,如果想知道模合数的结果,可以把合数先分解质因数成(互质的)质数的次幂,比如说 24=3×824 = 3 \times 8 而不是 24=3×2×2×224 = 3 \times 2\times 2\times 2

对于每个质数次幂单独求解,最后用中国剩余定理合并

所以处理没有平方因子的数的难度和质数是一样的

简介

一个整数除以3322,除以5533,除以7722,求这个整数。

将除以33得到的余数乘以7070,将除以55得到的余数乘以2121,将除以77得到的余数乘以1515,全部加起来後再减去105105或者105105的整数倍,得到的数就是答案(除以105105得到的余数则为最小答案)。使用以上的方法计算就得到
70×2+21×3+15×2=233=2×105+2370 \times 2 + 21 \times 3 + 15 \times 2 = 233 = 2 \times 105 + 23

所以最小的自然数解为2323
注意70,21,1570, 21, 15所满足的性质。
70mod3=1,70mod5=0,70mod7=070 \bmod 3 = 1, 70 \bmod 5 = 0, 70 \bmod 7 = 0
21mod3=0,21mod5=1,21mod7=021 \bmod 3 = 0, 21 \bmod 5 = 1, 21 \bmod 7 = 0
15mod3=0,15mod5=0,15mod7=115 \bmod 3 = 0, 15 \bmod 5 = 0, 15 \bmod 7 = 1

中国剩余定理

{xr1(modp1)xr2(modp2)xrn(modpn)\left\{ \begin{matrix} x \equiv r_1 \pmod {p_1} \\ x \equiv r_2 \pmod {p_2} \\ \vdots \qquad\qquad\qquad \\ x \equiv r_n \pmod {p_n} \end{matrix} \right.
对于每个ii求出mim_i使得mimodpj(ji)=0m_i \bmod p_j(j \neq i) = 0并且mimodpi=1m_i \bmod p_i = 1
最终答案就是irimi\sum_{i} r_i m_i
计算mim_i可以先通过计算P=ipiP = \prod_i p_iPpi\frac{P}{p_i}已经满足了第一个性质,但是不满足第二个性质,再乘以Ppi\frac{P}{p_i}pip_i的逆元就可以了。

扩展欧几里得

对于任意两个方程
{xr1(modp1)xr2(modp2)\left\{ \begin{matrix} x \equiv r_1 \pmod {p_1} \\ x \equiv r_2 \pmod {p_2} \\ \end{matrix} \right.
可以合并成一个modlcm(p1,p2)\bmod \mathrm{lcm}(p_1, p_2)的方程。
具体来说设x=k1p1+r1=k2p2+r2x = k_1 p_1 + r_1 = k_2 p_2 + r_2
k1p1k2p2=r2r1k_1 p_1 - k_2 p_2 = r_2 - r_1
用扩展欧几里得算法解出一组解(k1,k2)(k_1, k_2),就可以得到xmodlcm(p1,p2)x \bmod \mathrm{lcm}(p_1, p_2)的结果了。

这个做法不要求p1p_1p2p_2满足任何性质,是最通用的做法。

当然如果(r2r1)modgcd(p1,p2)0(r_2 - r_1) \bmod \gcd(p_1, p_2) \neq 0那么原方程无解。

实现技巧

如果取模的数字pip_i比较小,可以不实现逆元,直接O(ipi)O(\sum_{i} p_i)暴力一遍即可。
比如Luogu P1495

#include <bits/stdc++.h>
using namespace std;
int n, a[10], b[10];
long long m = 1, z;
int main() {
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i] >> b[i];
		m *= a[i];
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < a[i]; j++) {
			if (m / a[i] * j % a[i] == 1) {
				z += m / a[i] * j * b[i];
			}
/*
或者
			if (m / a[i] * j % a[i] == b[i]) {
				z += m / a[i] * j;
			}
*/
		}
	}
	cout << z % m << endl;
}

如果已知取模的数字pip_i,可以直接暴力计算出需要的mim_i,直接将mim_i写入程序中。
poj 1006
答案就是(5544p+14421e+1288id1)mod21252+1(5544p + 14421e + 1288i - d - 1) \bmod 21252 + 1

参考题目

Luogu P1495

poj 1006

bzoj 1951
组合数对9999116591=2×3×4679×35617999911659 - 1 = 2 \times 3 \times 4679 \times 35617 取模。

bzoj 2142
组合数对任意数取模,注意pici100000p_i^{c_i} \leq 100000

参考资料

Wikipedia 中国剩余定理

  1. 中国剩余定理
    1. 简介
    2. 中国剩余定理
    3. 扩展欧几里得
    4. 实现技巧
    5. 参考题目
    6. 参考资料