前言
本文将介绍几个和欧几里得 算法算法相关的算法,它们都使用了辗转相除 的计算策略,获得类似于 \(O(\log V)\)(\(V\) 为值域)的优秀复杂度。
本文将提供清晰的(数学公式用 \(\LaTeX\) 呈现的)伪代码。
约定
- 对于整数 \(x,y\),定义 \(z=x\bmod y\),当且仅当 \(z\) 是最小的非负整数 ,满足 \(y\mid (x-z)\)。中间一竖是整除符号。
求最大公约数
问题 :给定正整数 \(x,y\leq V\),求 \(\gcd(x,y)\)。(\(\gcd(x,y)\) 表示 \(x\) 和 \(y\) 的最大公约数)
解说 :若 \(x=y\),则平凡地,\(\gcd(x,y)=x\)。不妨设 \(x<y\),则显然有 \(\gcd(x,y)=\gcd(y-x,x)\),根据取模的定义,可得 \(\gcd(x,y)=\gcd(y\bmod x,x)\),于是就有做法了。
伪代码:(函数的返回值即为答案)
- function \(\text{solve}(x,y)\)
- if \(x=0\) then
- return \(y\)
- return \(\text{solve}(y\bmod x,x)\)
- if \(x=0\) then
复杂度分析 :设时间复杂度为 \(\mathcal{T}(x,y)\),现在我们证明如下命题:
- \(\displaystyle\exists x',y'\in \mathbb N^+,x'\leq \frac{x}{2},y'\leq y\),满足 \(\mathcal{T}(x,y)\leq \mathcal{T}(x',y')+O(1)\)。
如果该命题成立,就容易推出 \(\mathcal{T}(x,y)=O(\log V)\) 了。
不妨设 \(r=y\bmod x\),则分两种情况讨论。
- 若 \(\displaystyle r\leq\frac{x}{2}\),根据算法过程,\(\mathcal{T}(x,y)=\mathcal{T}(x,r)+O(1)=\mathcal{T}(r,x)+O(1)\),命题成立。
- 若 \(\displaystyle r>\frac{x}{2}\),则有 \(\mathcal{T}(x,y)=\mathcal{T}(r,x)+O(1)=\mathcal{T}(x\bmod r,x)+O(1)\),此时 \(\displaystyle x\bmod r=x-r\leq\frac{x}{2}\),故命题成立。
于是,该算法的复杂度为
\[\boxed{O(\log V)} \]
之后算法的复杂度都与它类似,将不再证明。
扩展欧几里得
问题 :给定正整数 \(a,b\leq V\),请求出关于 \((x,y)\) 的方程
\[ax+by=1 \]
的任意整数解(即满足 \(x,y\in\mathbb{Z}\)),保证有整数解。
解说 :当 \(a=b\) 是,方程无整数解,所以不妨设 \(a<b\)。直接将 \(b\) 写成带余除法形式
\[\begin{gathered} k=\lfloor\frac{b}{a}\rfloor\\ r=(b\bmod a)\\ b=ka+r \end{gathered} \]
将 \(b=ka+r\) 代入方程,整理得
\[ry+a(x+ky)=1 \]
可以将其看做关于 \((y,x+ky)\) 的方程,这样,原本的系数为 \(\displaystyle\left[\begin{matrix}a\\ b\end{matrix}\right]\) 的问题就能转化为系数为 \(\displaystyle\left[\begin{matrix}r\\ a\end{matrix}\right]\) 的问题。这样,算法就呼之欲出了。
伪代码:
- function \(\text{solve}(a,b)\)
- if \(a=0\) then
- return \((0,1)\)
- let \((x',y')= \text{solve}(b\bmod a,a)\)
- return \(\displaystyle (y'-\lfloor\frac{b}{a}\rfloor\times x',x')\)
- if \(a=0\) then
复杂度分析 :与欧几里得算法一样,\(O(\log V)\)。
生长 :如果想要更详细的了解该算法,参见裴蜀定理 - OI Wiki。
线性同余不等式约束下的最小值
问题 :给定正整数 \(a,m\)(\(a<m\))和非负整数 \(L\leq R<m\),请求出最小的非负整数 \(x\) 使得
\[L\leq ax\bmod m\leq R \]
若不存在这样的 \(x\),需要报告无解。
解说 :如果 \([L,R]\) 中有 \(a\) 的倍数,即满足 \(\displaystyle a\times\lceil\frac{L}{a}\rceil\leq R\) 时,\(x\) 显然为 \(\displaystyle\lceil\frac{L}{a}\rceil\)。
在其他情况下,不妨将问题转化,再添加一个变量 \(k\),问题变为:找到最小的非负整数 \(k\),使得存在非负整数 \(x\),满足
\[L\leq ax-km\leq R \]
因为这里的 \(k\) 相当于 \(\displaystyle\lfloor\frac{ax}{m}\rfloor\),所以当 \(k\) 最小时,\(x\) 可以取到最小的 \(\displaystyle \lceil\frac{L+km}{a}\rceil\)。
变形可得,存在 \(x\) 满足上述不等式,当且仅当
\[(-R)\bmod a\leq mk\bmod a\leq (-L)\bmod a \]
其中 \(mk\bmod a=(m\bmod a)k\bmod a\)。
所以算法就呼之欲出了。
伪代码:
- function \(\text{solve}(a,m,L,R)\)
- if \(L=0\) then
- return \(0\)
- if \(a=0\) or \(R<L\) then
- return 无解
- if \(\displaystyle a\times\lceil\frac{L}{a}\rceil\leq R\) then
- return \(\displaystyle\lceil\frac{L}{a}\rceil\)
- let \(k=\text{solve}(m\bmod a,a,(-R)\bmod a,(-L)\bmod a)\)
- if \(k=\) 无解 then
- return 无解
- return \(\displaystyle\lceil\frac{L+km}{a}\rceil\)
- if \(L=0\) then
时间复杂度 :同样是 \(O(\log V)\)。
帮助 :你可能需要这个式子 \(\displaystyle\lceil\frac{x}{y}\rceil=\lfloor\frac{x+y-1}{y}\rfloor\)(当 \(x,y\in \mathbb{Z},y>0\) 时成立)。
类欧几里得
问题 :给定非负整数 \(n,a,b,c\leq V\),满足 \(c\neq 0\),求
\[\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor \]
解决 :不妨设答案为 \(f(a,n,b,c)\),则当 \(a=0\) 时,有
\[f(a,n,b,c)=\lfloor\frac{b}{c}\rfloor\cdot (n+1) \]
当 \(a\geq c\) 或 \(b\geq c\) 时,有
\[\begin{gathered} f(a,b,c,n)=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\\ =\sum_{i=0}^n\left\lfloor\frac{(a\bmod c)i+(b\bmod c)}{c}\right\rfloor+\lfloor\frac{a}{c}\rfloor \cdot\frac{n(n+1)}{2}+\lfloor\frac{b}{c}\rfloor\cdot (n+1)\\ =f(a\bmod c,b\bmod c,c,n)+\lfloor\frac{a}{c}\rfloor \cdot \frac{n(n+1)}{2}+\lfloor\frac{b}{c}\rfloor\cdot (n+1) \end{gathered} \]
当 \(a<c\) 且 \(b<c\) 时,有(不妨设 \(\displaystyle m=\left\lfloor\frac{an+b}{c}\right\rfloor\))
\[\begin{gathered} f(a,b,c,n)=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\\ =\sum_{i=0}^n\sum_{j=0}^{m-1} [c(j+1)\leq ai+b]\\ =\sum_{j=0}^{m-1}\sum_{i=0}^n [ai> cj+c-b-1]\\ =\sum_{j=0}^{m-1}\left(n-\left\lfloor\frac{cj+c-b-1}{a}\right\rfloor\right)\\ =mn-\sum_{j=0}^{m-1}\left\lfloor\frac{cj+c-b-1}{a}\right\rfloor\\ =mn-f(c,c-b-1,a,m-1) \end{gathered} \]
然后就有做法了。
伪代码:
- function \(\text{solve}(a,b,c,n)\)
- if \(n=0\) then
- return \(\displaystyle \lfloor\frac{b}{c}\rfloor\)
- if \(a\geq c\) or \(b\geq c\) then
- return \(\displaystyle \text{solve}(a\bmod c,b\bmod c,c,n)+\lfloor\frac{a}{c}\rfloor \cdot \frac{n(n+1)}{2}+\lfloor\frac{b}{c}\rfloor\cdot (n+1)\)
- let \(\displaystyle m=\left\lfloor\frac{an+b}{c}\right\rfloor\)
- if \(m=0\) then ^[1]^
- return \(0\)
- return \(mn-\text{solve}(c,c-b-1,a,m-1)\)
- if \(n=0\) then
复杂度分析 :为 \(O(\log V)\)。
万能欧几里得
约定 :在本节中,部分运算将在群 \(G\) 下进行,所有的乘法运算 都可能被看做 \(G\) 的群乘法。
问题 :给定群元 \(e,r,s\in G\),其中 \(e\) 为单位元 ,给定函数(其中 \(a,b,c\in\mathbb{N},c\neq 0\))
\[\xi(x)=\frac{ax+b}{c} \]
函数 \(f: \mathbb{N}\to G\) 的定义见下方伪代码。给定非负整数 \(n\leq V\),请求出 \(f(n)\) 的值。
下方伪代码中,\(\epsilon\) 为无穷小的正数。
- function \(f(n)\)
- let \(x=\epsilon\), \(\text{ans}=e\)
- while \(x\leq n\) do
- if \(\xi(x)\in\mathbb Z\) then
- \(\text{ans}\gets \text{ans}\times r\)
- if \(x\in\mathbb Z\) then
- \(\text{ans}\gets \text{ans}\times s\)
- \(x\gets x+\epsilon\)
- if \(\xi(x)\in\mathbb Z\) then
- return \(\text{ans}\)
假设群 \(G\) 的乘法能做到单次 \(O(T)\) 的复杂度。
解说 :当 \(n=0\) 时,平凡的,\(f(0)=e\)。
不妨设答案为 \(g(a,b,c,n,r,s)\)。
容易发现,把 \(\xi\) 所代表的的直线向下平移是没有影响的,即
\[g(a,b,c,n,r,s)=g(a,b\bmod c,c,n,r,s) \]
这里不妨设 \(b<c\)。
当 \(a\geq c\) 时,尝试让一方模另一方 。根据 \(f\) 差分的周期性,有:
\[g(a,b,c,n,r,s)=g(a\bmod c,b,c,n,r,r^{\lfloor\frac{a}{c}\rfloor} \times s) \]
可以使用 \(f\) 的几何意义 直观理解该式。可以把 \(f\) 看成一条欧氏平面中的直线,是否乘 \(r\) 或 \(s\) 取决于直线上某点的纵坐标或横坐标是否是整数。发现每次给 \(\text{ans}\) 乘上 \(s\) 前先至少要乘 \(\displaystyle \lfloor\frac{a}{c}\rfloor\) 个 \(r\)。
当 \(a<c\) 时,尝试交换它们。
考虑直接将 \(\text{ans}\) 写成求积形式,有
\[\text{ans}=\prod_{i=1}^n r^{\lfloor\xi(i)\rfloor-\lfloor\xi(i-1)\rfloor}\times s \]
为了方便研究,用字符串表示群元 ,群乘法表示为字符串的拼接 ,设 \(e\) 为空字符串 ,\(r=\texttt{r}\),\(s=\texttt{s}\),则 \(\text{ans}\) 为一个由 \(\texttt{r}\) 和 \(\texttt{s}\) 构成的字符串。
比较显然的是,\(\text{ans}\) 中,第 \(i\) 个 \(\texttt{s}\) 前有 \(\lfloor\xi(i)\rfloor\) 个 \(\texttt{r}\)。为了达到交换效果,我们不妨计算 \(\text{ans}\) 中,第 \(j\) 个 \(\texttt{r}\) 前面有几个 \(\texttt{s}\)。容易列出式子,答案为下方不等式中,整数 \(t\) 的最大值。
\[\left\lfloor\frac{at+b}{c}\right\rfloor<j \]
它是
\[\frac{at+b}{c}<j \]
解不等式得 \(t\) 的最大值为
\[\left\lfloor\frac{c(j-1)+c-b-1}{a}\right\rfloor \]
不妨设函数 \(\displaystyle \xi'(x)=\frac{cx+c-b-1}{a}\)。
于是 \(\text{ans}\) 可以被表示为(不妨设 \(m=\lfloor\xi(n)\rfloor\))
\[\begin{gathered} \text{ans}=s^{\lfloor\xi'(1-1)\rfloor}\times r\times\left(\prod_{j=2}^{m} s^{\lfloor\xi'(j-1)\rfloor-\lfloor\xi'((j-1)-1)\rfloor} \times r\right) \times s^{n-\lfloor\xi'(m-1)\rfloor}\\ =s^{\lfloor\xi'(0)\rfloor}\times r\times \left(\prod_{j=1}^{m-1}s^{\lfloor\xi'(j)\rfloor-\lfloor\xi'(j-1)\rfloor} \times r\right)\times s^{n-\lfloor\xi'(m-1)\rfloor}\\ =s^{\left\lfloor\frac{c-b-1}{a}\right\rfloor}\times r\times g(c,c-b-1,a,m-1,s,r)\times s^{n-\lfloor\xi'(m-1)\rfloor}\\ =s^{\left\lfloor\frac{c-b-1}{a}\right\rfloor}\times r\times g(c,(c-b-1)\bmod a,a,m-1,s,r)\times s^{n-\left\lfloor\frac{cm-b-1}{a}\right\rfloor}\\ \end{gathered} \]
然后就有做法了。
伪代码:
- function \(\text{solve}(a,b,c,n,r,s)\)
- if \(n=0\) then
- return \(e\)
- if \(a\geq c\) or \(b\geq c\) then
- return \(\text{solve}(a\bmod c,b\bmod c,c,n,r,r^{\lfloor\frac{a}{c}\rfloor}\times s)\)
- let \(\displaystyle m=\left\lfloor\frac{an+b}{c}\right\rfloor\)
- if \(m=0\) then
- return \(s^n\)
- return \(s^{\left\lfloor\frac{c-b-1}{a}\right\rfloor}\times r\times g(c,(c-b-1)\bmod a,a,m-1,s,r)\times s^{n-\left\lfloor\frac{cm-b-1}{a}\right\rfloor}\)
- if \(n=0\) then
复杂度分析 :如果群元的次幂可以 \(O(T)\) 计算,那么时间复杂度就是 \(O(T\log V)\) 的。如果不可以,那么可以使用快速幂 - OI Wiki算法做到单次 \(O(T\log V)\),那么时间复杂度有上界 \(O(T\log^2 V)\)。
实际上,有更紧的上界,设时间复杂度为 \(\mathcal{T}(a,c)\),则有
\[\mathcal{T}(a,c)=O(T\log \frac{a}{c})+\mathcal{T}(c\bmod a,a) \]
考虑到 \(\displaystyle O(T\log \frac{a}{c})=O(T\log a)-O(T\log c)\),所以,将 \(\mathcal{T}(a,c)\) 直接展开后,含有 \(\log\) 的项会消得只剩 \(O(1)\) 个,于是复杂度就是
\[\boxed{O(T\log V)} \]
完结撒花。
- 实际上,这个条件判断可以去掉,因为 \(n<0\) 时不会让该算法错误。 ↩︎