void ex_gcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1;
y = 0;
} else {
ex_gcd(b, a % b, y, x);
y -= a / b * x;
}
}
快速幂:要求 m 为素数
根据费马小定理 a*a^{m-2}=a^{m-1}\equiv 1\pmod m
以及逆元的唯一性可知,逆元 a^{-1}\bmod p 就等于 a^{p-2}\bmod p,因此可以直接使用 快速幂 在 O(\log p) 时间内计算:
int qpow(int a, int b, int m) {
long long res = 1, po = a;
for (; b; b >>= 1) {
if (b & 1) res = res * po % m;
po = po * po % m;
}
return res;
}
int inverse(int a, int p) { return qpow(a, p - 2, p); }
多个逆
线性递推求逆:
同余方程组
𝑥 ≡𝑎1(mod𝑛1)
𝑥 ≡𝑎2(mod𝑛2)
⋮
𝑥 ≡𝑎𝑘(mod𝑛𝑘)
求同余方程组的解
中国剩余定理 CRT
此方法只适用于模数互质的情况,步骤:
计算总模数 M = 各个模数之积
计算 m_{i}=\frac{M}{n_{i}}
方程在模 M 意义下的唯一解:x=\sum_{i=1}^{n}a_{i}\times m_{i}\times m_{i}^{-1}(mod M)
for(int i=1;i<=n;i++){
read(a[i]); read(b[i]);
M = M * a[i];//模数的乘积
}
for(int i=1;i<=n;i++){
__int128 m = M / a[i],x,y;//模数积除以各自的模数
exgcd(m,a[i],x,y);//exgcd计算m的逆元
ans = (ans + b[i] * m * x % M) % M;//m * m^-1 * 权值 取模总模数
}
接下来证明分块少于 2\sqrt n 种。
当 i <= \sqrt n 时,\lfloor\frac{n}{i}\rfloor 的值大于等于 \sqrt n,共 \sqrt n 个;当 i > \sqrt n 时,\lfloor\frac{n}{i}\rfloor < \sqrt n,也有 \sqrt n 个。
当一个区间内的值为 k 时,区间右端点为 \lfloor\frac{x}{k}\rfloor,证明略。
ll get(ll x){
ll res = 0;
for(ll i=1,j;i<=x;i=j+1){
j = x / (x / i);
res += (x/i) * (j - i + 1);
}
return res;
}
和上面的结论一样,根据整除分块,\lfloor\frac{n}{i}\rfloor 相同的 a 是连续的一段,且只有 sqrt_{n} 级别,注意到 i \mod j 在这相同的一段中是公差为 \lfloor\frac{n}{i}\rfloor 的等差数列的形式,所以说我们就可以利用根号分治的思想,小于根号 k 的暴力计算,大于根号 k 的进行下标的等差数列前缀和预处理,利用整除分块快速计算。