2025-11-7 10:20:00 TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.

笔记

数学

狭窄的过道旁

我将树根编织成楼宇

藏起枝丫

你盛放于微风中那摇曳的模样

交换免于摧折的时光

同余

欧几里得算法

定理内容

\[\forall a,b\in\mathbb{N},b\not=0,\quad\gcd(a, b) = \gcd(b, a \bmod b) \]

证明

  1. \(a\lt b\),则 \(\gcd(b, a\bmod b) = \gcd(b, a) = \gcd(a, b)\)
  2. 否则,令 \(a = k \times b + a\bmod b\),有 \(\gcd(a, b) | a, \gcd(a, b)|k\times b\),显然 \(\gcd(a, b)\mid(a - k\times b)\),即 \(gcd(a, b)\mid a\bmod b\)

综上所述 \(\forall a,b\in\mathbb{N},b\not=0,\quad\gcd(a, b) = \gcd(b, a \bmod b)\)

根据该定理,可以写出求最大公约数的代码。

int gcd(int a, int b) {
  return b ? gcd(b, a % b) : a; // gcd(a, 0) = a
}

裴蜀定理

定理内容

\[\forall a, b\in \mathbb{Z},\quad\exist x, y\in \mathbb{Z},ax+by = \gcd(a, b) \]

证明

在欧几里得算法的最后,有 \(x = 1, y = 0\),满足 \(a \times 1 + b\times 0 = a = \gcd(a, 0)\)

在欧几里得算法过程中,如果存在整数 \(x, y\),满足 \(b\times x +(a\bmod b)\times y = \gcd(b, a \bmod b) = \gcd(a, b)\),则令 \(x' = y, y' = x - \lfloor \frac{a}{b}\rfloor\times y\)\(ax'+by' = \gcd(a, b)\)

根据上述,总有 \(ax + by = \gcd(a, b)\)

应用

两个互质的数 \(a, b\),\(\{p\mid p = ax + by,x\in \mathbb{Z},y\in\mathbb{Z}\} = \mathbb{Z}\)

这是因为存在一对 \(x, y\),满足 \(ax + by = 1\)。则 \(kax+kby = k, k\in \mathbb{Z}\)

集合 \(M = \{u\mid u = 12m+8n+4l,\ m, n, l\in \mathbb{Z}\}\) 与集合 \(N = \{u\mid u = 20p + 16q + 12r,\ p,q,r\in \mathbb{Z}\}\) 的关系是__ 。

\(M = N\)

\(\because M = \{u\mid u = 4(3m+2n+l)\}, N = \{u\mid u = 4(5p+4q+3r)\}\),其中 \((3, 2, 1) = 1, (5, 4, 3) = 1\)

由裴蜀定理可知,\(M = N = \{t\mid 4t ,\ t \in \mathbb{Z}\}\)

欧拉定理

费马小定理

内容:\(\forall p \in \mathbb P \land a \bot p\),有 \(a^{p - 1}\equiv 1 \pmod p\)

这说明在模 \(p\) 意义下,\(\forall x, k \in \mathbb R,a^x \equiv a^{kp+x}\pmod p\) 。即 \(a^{x} \equiv a^{x \bmod p}\pmod p\)

欧拉定理

欧拉函数

定义:在 \(1\)\(n\) 中,有 \(\varphi(n)\) 个数和 \(n\) 互质。

计算:对 \(n\) 做质因数分解,记 \(n = p_1^{k1} \times p_2^{k_2} \times \cdots \times p_m^{k_m}\)

\[\varphi(n) = n \times \prod_{i = 1}^m({1 - \frac{1}{p_i}}) \]

$\mathcal{O(\sqrt{n})}$ code
int phi(int n) {
  int res = n;
  
  rep(i, 2, sqrt(n)) if (n % i == 0) {
    res = res / i * (i - 1);
    while (n % i == 0) n /= i;
  }
  
  if (n > 1) res = res / n * (n - 1); // 一个数至多有一个比 \sqrt{n} 大的质数
  return res;
}
欧拉定理

如果 \((a, p) = 1\),有 \(a^{\varphi(p)} \equiv 1 \pmod p\)

类比费马小定理,有 \(a^x\equiv a^{x \bmod \varphi(p)} \pmod p\)

拓展欧拉定理

\(\forall a, b \in \mathbb Z,a^b \equiv a^{b \bmod \varphi(p) + \varphi(p)}\pmod p\)

中国剩余定理(CRT)

中国剩余定理(Chinese Remainder Theorem,CRT)用于求解模数两两互质的线性同余方程组。

\[\begin{cases} x \equiv a_1& \pmod {m_1}\\ x \equiv a_2& \pmod {m_2}\\ &\vdots\\ x \equiv a_n& \pmod {m_n}\\ \end{cases} \]

CRT 的思想是求出若干个数,使得这些数依次满足每个同余方程,且在其它模数下均为 \(0\),则这些数的和即为所求。

\(M = \prod\limits_{i = 1}^{n} m_i, c_i = \dfrac{M}{m_i}\)\(d_i\)\(c_i\)\(m_i\) 意义下的逆元,得 \(x_i = a_ic_id_i\)。得到特解为 \(z = \sum\limits_{i = 1}^nx_i\)。通解即 \(z + kM,\,k\in\mathbb{Z}\)

$\mathcal{O(n \log m)}$ code
int n, a[N], b[N];
i64 M, ans;

void exgcd(int a, int b, int &x, int &y) {
  if (!b) return x = 1, y = 0, void();
  exgcd(b, a % b, y, x) y -= a / b * x;
}

int inv(int x, int p) {
  return exgcd(x, p, x, *new int), (x % p + p) % p;
}

void CRT() {
  rep(i, 1, n) M *= m[i];
  rep(i, 1, n) ans = (ans + a[i] * M / m[i] * inv(M / m[i] % m[i], m[i]))
}

拓展中国剩余定理

和中国剩余定理没有什么关系,不是吗。

当模数不互质时,合并两个同余方程 \(x\equiv a_1\pmod {m_1}\)\(x \equiv a_2 \pmod {m_2}\)

因为 \(x\) 可以表示成 \(a_1+pm_1\),所以 \(a_1+pm_1\equiv a_2 \pmod {m_2}\),即 \(pm_1+qm_2\equiv a_2−a_1\pmod {m_2}\),exgcd 求解 \(p\) 即可。

也可以理解为 \(p\equiv \dfrac{a_2−a_1}{m_1}\pmod {m2}\) 并使用 exgcd 求逆元。

合并后的方程为

\[x \equiv a_1+pm_1 \pmod {\text{lcm}(m_1,m_2)} \]

根据 Bezout 定理,若 \(\gcd(m_1,m_2) \nmid a_2−a_1\),方程组无解。

$\mathcal{O}(k \log V)$ code
int n;
i64 a1, m1, a2, m2, p;

i64 mul(i64 a, i64 b, i64 mod) {
  i64 res = 0;

  for (; b; b >>= 1) {
    if (b & 1) res = (res + a) % mod;
    a = (a + a) % mod;
  }

  return res;
}

i64 exgcd(i64 a, i64 b, i64 &x, i64 &y) {
  if (!b) return x = 1, y = 0, a;
  i64 d = exgcd(b, a % b, y, x); y -= a / b * x;
  return d;
}

void exCRT() {
  read(m1, a1);

  rep(i, 1, n - 1) {
    read(m2, a2);
    i64 d = exgcd(m1, m2, p, *new i64);
    i64 dif = ((a2 - a1) % m2 + m2) % m2;  
    if (dif % d) { return puts("-1"), void(); }
    p = mul(p, dif / d, m2); i64 lcm = m1 / d * m2;
    a1 = (mul(p, m1, lcm) + a1) % lcm;
    m1 = lcm; a1 = (a1 % lcm + lcm) % lcm;
  }

  write(a1);
}

注意龟速乘 b 不要传负数

题目

P2480 [SDOI2010] 古代猪文

题目要求 \(ans = g^{\sum_{d \mid n}\begin{pmatrix}n\\d\end{pmatrix}} \bmod 999911659\)。由欧拉定理容易得 \(ans \equiv g^{\sum_{d \mid n}\begin{pmatrix}n\\d\end{pmatrix}\bmod 999911658} \bmod 999911659\)

显然求出 \(\sum_{d \mid n}\begin{pmatrix}n\\d\end{pmatrix}\bmod 999911658\) 后可以用快速幂。同时 \(999911658 = 2 \times 3 \times 4679 \times 35617\),不能用 Lucas 定理。但是对四个质因子分别应用 Lucas 定理,可以得到一个满足 CRT 的线性同余方程组。即

\[\begin{cases}x\equiv \begin{pmatrix}n\\d\end{pmatrix}\pmod 2\\x\equiv \begin{pmatrix}n\\d\end{pmatrix}\pmod 3\\x\equiv \begin{pmatrix}n\\d\end{pmatrix}\pmod {4679}\\x\equiv \begin{pmatrix}n\\d\end{pmatrix}\pmod {35617}\end{cases} \]

运用一下 exCRT 的思想,实际上求出的 \(x\) 满足 \(x \equiv \begin{pmatrix}n\\d\end{pmatrix}\pmod{999911659}\)

剩下的就简单了。code

注意到欧拉定理应用于 \(g\bot 999911659\),而 \(g\in [1, 1\times 10^9]\),可能相等,需要特判。

但loj并没有这个数据

大步小步算法(BSGS)

解决已知 \(a, b, p\)\(x\) 使得 \(a^x = b \pmod p\) 的问题。

BSGS 要求 \(a \perp p\)。BSGS 使用了 meet-in-middle 的算法。由欧拉定理,\(x \in [0, p - 1]\)。记 \(M\) 为设定的步长, \(x\) 可表示为 \(AM - B\),则 \(a^{AM - B} \equiv b\pmod p\),即 \(a^{AM} \equiv a^Bb\),考虑枚举 \(a^{AM}\)\(a^Bb\) 的值,通哈希判断是否存在 \(A,B\) 使两个值相等。时间复杂度 \(\mathcal{O}(\max\{A, B\})\)

因为 \(B \in [1, M], A \in [1, \lceil \frac{p - 1}{M}\rceil]\),当 \(M\)\(\sqrt{q}\) 时时间复杂度为 \(\mathcal{O}(\sqrt{q})\)

code
int a, b, p, ans;

int BSGS(int a, int b, int p) {
  int GS = 1, M = sqrt(p) + 1, BS;
  GS %= p, M %= p;
  unordered_map<int, int> hash;
  
  rep(i, 1, M) {
    GS = (i64)GS * a % p;
    hash[(i64)GS * b % p] = i;
  }

  BS = GS;
  rep(i, 1, M) {
    if (hash.find(BS) != hash.end()) {
      return i * M - hash[BS];
    }

    BS = (i64)BS * GS % p;
  }

  return -1;
}

整除分块/数论分块

可以快速计算一些含有除法向下取整的和式(即形如\(\sum\limits_{i=1}^nf(i)g(\left\lfloor\dfrac ni\right\rfloor)\)的和式。

结论:对于常数 \(n\),设一块的左边界是 \(l\),则右边界为 \(\left\lfloor n/{\lfloor n/l\rfloor}\right\rfloor\)

因为最多有 \(2\sqrt{n}\) 种取值,故时间复杂度为 \(\mathcal{O}(\sqrt{n})\)

P2261 [CQOI2007] 余数求和
int n, k;
i64 ans;

int main() {
  read(n, k);
  ans = (i64)n * k;

  for (int l = 1, r; l <= n; l = r + 1) {
    r = k / l ? min(k / (k / l), n) : n;
    ans -= (i64)(l + r) * (r - l + 1) * (k / l) / 2;
  }

  write(ans);
  return 0;
}

离散与组合数学

把月历撕下

把伤口缝上

被营养液浸透变得湿润的土壤

组合数学

【Mayday】

我将书册留在了仓库

温度将我宽恕

【M'aider】

也安然眠于摇篮椅

而我将走向终末

定义

加法原理

完成一件事有 \(n\) 种不同途径,每种途径有 \(m_i\) 种不同方式。则完成这件事有 \(\sum\limits_{i = 1} ^ nm_i\) 种方式。

乘法原理

完成一件事有 \(n\) 个步骤,每个步骤有 \(m_i\) 种不同完成方式。则完成这件事有 \(\prod \limits_{i = 1}^nm_i\) 种方式。

排列与组合

排列:从 \(n\) 个元素中按照一定的顺序取出 \(m\) 个不同元素的方案数,记作 \(A_n^m\)\(A_n^m = \dfrac{n!}{(n - m)!}\)

组合:从 \(n\) 个元素中取出 \(m\) 个不同元素的方案数,记作 \(C_n^m\)\(C_n^m = \dfrac{n!}{(n - m)!m!}\)

圆排列:从 \(n\) 个元素中选出 \(m\) 个不同元素围成一个圆的方案数,记作 \(Q_n^m\)\(Q_n^m = \dfrac{A_n^m}{m}\)

性质

性质一

\[\begin{pmatrix}n\\m\end{pmatrix}=\begin{pmatrix}n-1\\m\end{pmatrix}+\begin{pmatrix}n-1\\m-1\end{pmatrix} \]

性质二

\[\begin{pmatrix}n\\m\end{pmatrix}=\begin{pmatrix}n\\n-m\end{pmatrix} \]

性质三

\[\begin{pmatrix}n+m+1\\m\end{pmatrix}= \sum_{i = 0}^m\begin{pmatrix}n+i\\i\end{pmatrix} \]

性质四

\[\begin{pmatrix}n\\m\end{pmatrix}\times\begin{pmatrix}m\\r\end{pmatrix}=\begin{pmatrix}n\\r\end{pmatrix}\times\begin{pmatrix}n-r\\m-r\end{pmatrix} \]

性质五

\[m\times\begin{pmatrix}n\\m\end{pmatrix}=n\times\begin{pmatrix}n-1\\m-1\end{pmatrix} \]

性质六

\[\sum_{i = 0}^m\begin{pmatrix}m\\i\end{pmatrix}x^i=(x+1)^m\\ \sum_{i = 0}^m\begin{pmatrix}m\\i\end{pmatrix}=2^m \]

性质七

\[\sum_{i = 0}^m(-1)^i\begin{pmatrix}m\\i\end{pmatrix}=0 \]

LUCAS 定理

\(p \in \mathbb{P}\)\(\forall m, n \in \mathbb{Z}, 1 \le m \le n\),有

\[\begin{pmatrix}n \\ m\end{pmatrix} \equiv \begin{pmatrix} n\bmod p\\m\bmod p\end{pmatrix}\times\begin{pmatrix}n/p\\m/p\end{pmatrix}\pmod p \]

用于处理 \(n, m\) 较大,而 \(p\) 较小的情况。

$\mathcal{O}(p + \log n)$ code
int T, n, m, p;
int fac[N], inv[N], ifac[N];

void init() {
  fac[0] = 1; rep(i, 1, p) fac[i] = (i64)fac[i - 1] * i % p;
  inv[1] = 1; rep(i, 2, p) inv[i] = (i64)(p - p / i) * inv[p % i] % p;
  ifac[0] = 1; rep(i, 1, p) ifac[i] = (i64)ifac[i - 1] * inv[i] % p;
}

int C(int n, int m) {
  if (m < 0 || n < 0 || m > n) return 0;
  if (m == 0) return 1;
  return (i64)fac[n] * ifac[m] % p * ifac[n - m] % p;
}

int lucas(int n, int m, int p) {
  if (n < p && m < p) return C(n, m);
  return (i64)lucas(n / p, m / p, p) * C(n % p, m % p) % p;
}
posted @ 2025-07-16 08:00  FRZ_29  阅读(48)  评论(0)    收藏  举报