数论
Miller-Rabin
先判掉 \(2\)。\(n - 1 = 2^rd\),取 \(1 \le a < n\)。若 \(n\) 为质数,则 \(a^d \equiv 1 \pmod{n}\) 和 \(\exist 0 \le i < r,\ a^{2^id} \equiv n - 1 \pmod{n}\) 至少一条成立,多次检测。
代码
bool isp(ll n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 == 0) return false;
int r = __builtin_ctzll(n - 1);
ll d = (n - 1) >> r;
for (auto a : {2, 325, 9375, 28178, 450775, 9780504, 1795265022}) {
if (a % n == 0) continue;
ll v = qpow(a, d, n);
if (v == 1) continue;
bool ok = false;
for (int i = 0; i < r; i++) {
if (v == n - 1) {
ok = true;
break;
}
v = i128(v) * v % n;
}
if (!ok) return false;
}
return true;
}
CRT & exCRT
\(n\) 个方程 \(x \equiv a_i \pmod{m_i}\),\(m_i\) 两两互质。
令 \(M = \prod m_i\),先解形如
的 \(n\) 个方程组,则 \(x \equiv \sum a_i x_i \pmod{M}\)。
不保证 \(m_i\) 互质时,考虑合并 \(x \equiv a \pmod{b}\) 和 \(x \equiv c \pmod{d}\):
用 exgcd 解出一组解 \(s_0, t_0\),则
带入 \(x = bs + a\),得
依次合并 \(n\) 个方程即可。
代码
bool merge(ll& a, ll& b, ll c, ll d) {
ll s, t, g = exgcd(b, d, s, t);
if ((c - a) % g) return false;
ll lcm = b / g * d;
s = i128(s) * ((c - a) / g) % lcm;
if (s < 0) s += lcm;
a = (i128(b) * s + a) % lcm, b = lcm;
return true;
}
只判断是否有解且答案会爆 ll:设 \(m_i\) 的标准分解为 \(p_1^{e_1}p_2^{e_2} \dots p_k^{e_k}\),由 CRT,\(x \equiv a_i \pmod{m_i}\) 可拆成
将所有拆出的方程按模的质数分组,不同组之间模数互质,不会矛盾,所以只需检查每组内是否有解即可。
代码
void solve() {
int n;
cin >> n;
map<int, vector<pair<int, int>>> mp;
for (int i = 1; i <= n; i++) {
int a, m;
cin >> a >> m;
for (int j = 2; j * j <= m; j++) {
if (m % j == 0) {
int pw = 1;
while (m % j == 0) m /= j, pw *= j;
mp[j].push_back({pw, a % pw});
}
}
if (m != 1) mp[m].push_back({m, a % m});
}
for (auto it : mp) {
auto eqs = it.second;
int v = max_element(eqs.begin(), eqs.end())->second;
for (auto eq : eqs) {
if (v % eq.first != eq.second) {
cout << "No\n";
return;
}
}
}
cout << "Yes\n";
}
BSGS
\(a^x \equiv b \pmod{p}\),\(p\) 为质数。
由费马小定理 \(a^{p - 1} \equiv a^0 \pmod{p}\) 可将解的范围缩小至 \([0, p - 1)\)。设置一个阈值 \(s\),将 \(0 \sim s - 1\) 设为第 \(1\) 组,\(s \sim 2s - 1\) 设为第 \(2\) 组,以此类推。把 \(a^0, a^1, \ldots, a^{s - 1}\) 扔进 map,枚举每一组,查询 \(\frac{b}{a^{is}}\) 即可。时间复杂度在 \(s = \sqrt{p}\) 时取到最小值 \(O(\sqrt{p} \log \sqrt{p})\)。
代码
int bsgs(int a, int b, int p) {
int s = sqrt(p) + 1;
map<int, int> mp;
int pw = 1;
for (int i = 0; i < s; i++) mp[pw] = i, pw = ll(pw) * a % p;
int inv = qpow(qpow(a, s, p), p - 2, p);
for (int i = 0; i < s; i++) {
if (mp.count(b)) return i * s + mp[b];
b = ll(b) * inv % p;
}
return -1;
}
狄利克雷卷积
-
定义:\((f * g)(n) = \sum_{d \mid n} f(d)g(\frac{n}{d})\)
-
有交换律、结合律、分配律。
-
若 \(f\)、\(g\) 均为积性函数,则 \(f * g\) 为积性函数。
-
\(\varepsilon * f = f\)(\(\varepsilon(n) = [n = 1]\))
-
\(\mu * \mathbf{1} = \varepsilon\)(\(\mathbf{1}(n) = 1\))
-
\(\varphi * \mathbf{1} = \operatorname{id}\)(\(\operatorname{id}(n) = n\))
证明:对任意 \(d \mid n\),\(\gcd(x, n) = d \iff \gcd(\frac{x}{d}, \frac{n}{d}) = 1\),所以 \(1 \sim n\) 中有 \(\varphi(\frac{n}{d})\) 个 \(x\) 满足 \(\gcd(x, n) = d\),所以 \((\varphi * \mathbf{1})(n) = \sum_{d \mid n} \varphi(d) = \sum_{d \mid n} \varphi(\frac{n}{d}) = n = \operatorname{id}(n)\)。 -
\(\mu * \operatorname{id} = \varphi\)
-
\(f = g * \mathbf{1} \iff g = f * \mu\)(莫比乌斯反演)

浙公网安备 33010602011771号