线性同余方程
https://en.wikipedia.org/wiki/Chinese_remainder_theorem
任何情况下,如果想知道模合数的结果,可以把合数先分解质因数成(互质的)质数的次幂,比如说 24=3×8 而不是 24=3×2×2×2
对于每个质数次幂单独求解,最后用中国剩余定理合并
所以处理没有平方因子的数的难度和质数是一样的
一个整数除以3余2,除以5余3,除以7余2,求这个整数。
将除以3得到的余数乘以70,将除以5得到的余数乘以21,将除以7得到的余数乘以15,全部加起来後再减去105或者105的整数倍,得到的数就是答案(除以105得到的余数则为最小答案)。使用以上的方法计算就得到
70×2+21×3+15×2=233=2×105+23
所以最小的自然数解为23。
注意70,21,15所满足的性质。
70mod3=1,70mod5=0,70mod7=0
21mod3=0,21mod5=1,21mod7=0
15mod3=0,15mod5=0,15mod7=1
⎩⎨⎧x≡r1(modp1)x≡r2(modp2)⋮x≡rn(modpn)
对于每个i求出mi使得mimodpj(j=i)=0并且mimodpi=1。
最终答案就是∑irimi。
计算mi可以先通过计算P=∏ipi,piP已经满足了第一个性质,但是不满足第二个性质,再乘以piP模pi的逆元就可以了。
对于任意两个方程
{x≡r1(modp1)x≡r2(modp2)
可以合并成一个modlcm(p1,p2)的方程。
具体来说设x=k1p1+r1=k2p2+r2
k1p1−k2p2=r2−r1
用扩展欧几里得算法解出一组解(k1,k2),就可以得到xmodlcm(p1,p2)的结果了。
这个做法不要求p1和p2满足任何性质,是最通用的做法。
当然如果(r2−r1)modgcd(p1,p2)=0那么原方程无解。
如果取模的数字pi比较小,可以不实现逆元,直接O(∑ipi)暴力一遍即可。
比如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];
}
}
}
cout << z % m << endl;
}
如果已知取模的数字pi,可以直接暴力计算出需要的mi,直接将mi写入程序中。
poj 1006
答案就是(5544p+14421e+1288i−d−1)mod21252+1
Luogu P1495
poj 1006
bzoj 1951
组合数对999911659−1=2×3×4679×35617 取模。
bzoj 2142
组合数对任意数取模,注意pici≤100000。
Wikipedia 中国剩余定理