类欧几里得算法学习笔记

类欧几里得算法

类欧几里得算法主要利用了分数的递归结构,不断进行迭代,而由于这和欧几里得算法有直接联系而得名。

引入:Fraction

给定 \(a, b, c, d\),求字典序最小的 \((q, p)\) 满足:

\[\dfrac{a}{b} < \dfrac{q}{p} < \dfrac{c}{d} \]

首先若

\[\lfloor\dfrac{a}{b}\rfloor + 1 < \dfrac{c}{d} \]

那么直接取 \((q, p) = (1, \lfloor\dfrac{a}{b}\rfloor + 1)\) 即可,显然最小。
否则,显然有

\[\lfloor\dfrac{a}{b}\rfloor \le \dfrac{a}{b} < \dfrac{q}{p} < \dfrac{c}{d} \le \lfloor\dfrac{a}{b}\rfloor + 1 \]

于是 \(\dfrac{q}{p}\) 的整数部分为 \(\lfloor\dfrac{a}{b}\rfloor\),然后全部减去 \(\lfloor\dfrac{a}{b}\rfloor\) 再取倒数,即求出

\[\dfrac{d}{c - d\lfloor\dfrac{a}{b}\rfloor}< \dfrac{q}{p-q\lfloor\dfrac{a}{b}\rfloor} < \dfrac{b}{a-b\lfloor\dfrac{a}{b}\rfloor} \]

\[\dfrac{d}{c - d\lfloor\dfrac{a}{b}\rfloor}< \dfrac{q}{p-q\lfloor\dfrac{a}{b}\rfloor} < \dfrac{b}{a \bmod b} \]

但是现在有一个问题:这样迭代求得的是 \((p, q)\) 字典序最小的解,但是我们要求的是 \((q, p)\) 字典序最小的解,事实上这两个解一定是同一个,如果不同,假设 \(p/q\)\((q, p)\) 字典序最小的一组解,\(r/s\) 是字典序 \((r, s)\) 最小的一组解,\(r/s \neq p/q\),那么显然 \(r < p, q < s\),即

\[\dfrac{a}{b} < \dfrac{r}{s} < \dfrac{r}{q} < \dfrac{p}{q} < \dfrac{c}{d} \]

所以 \(\dfrac{r}{q}\) 满足条件且无论以哪种字典序都更优。

时间复杂度 \(\mathcal{O}(\log\min(p, q))\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 2e5 + 10, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
    cout << arg << ' ';
    dbg(args...);
}
namespace Loop1st {
void solve(int a, int b, int &p, int &q, int c, int d) {
    if ((a / b + 1) * d < c) {
        p = a / b + 1;
        q = 1;
        return ;
    }
    solve(d, c - d * (a / b), q, p, b, a % b);
    p += q * (a / b);
} // 因为 a, b, c, d < 10 ^ 9, a / b < c / d 所以 int 足够了
void main() {
    int a, b, c, d, p, q;
    while (cin >> a >> b >> c >> d) {
        solve(a, b, p, q, c, d);
        cout << p << '/' << q << '\n';
    }
}

}
int main() {
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--) Loop1st::main();
    return 0;
}

Floor_Sum 问题

\(f(a, b, c, n) = \sum\limits_{i=0}^n\left\lfloor\dfrac{ai+b}{c}\right\rfloor\)
其中 \(a, b, c, n \in \mathbb{N}^*\)

代数推导

首先将问题转化为 \(a < c, b < c\) 的情形:

\[f(a, b, c, n) = \sum\limits_{i=0}^n\left\lfloor\dfrac{ai+b}{c}\right\rfloor \]

\[=\sum\limits_{i=0}^n\left\lfloor \dfrac{(\lfloor\dfrac{a}{c}\rfloor c+(a\bmod c))i + (\lfloor\dfrac{b}{c}\rfloor c+(b\bmod c))}{c}\right\rfloor \]

\[=\sum\limits_{i=0}^n\left\lfloor\dfrac{a}{c}\right\rfloor i+\left\lfloor\dfrac{b}{c}\right\rfloor + \left\lfloor \dfrac{(a\bmod c)i + (b\bmod c)}{c}\right\rfloor \]

\[=\dfrac{n(n+1)}{2}\left\lfloor\dfrac{a}{c}\right\rfloor+ (n+1)\left\lfloor\dfrac{b}{c}\right\rfloor+ f(a\bmod c, b\bmod c, c, n)\]

然后考虑 \(a < c, b < c\) 的情况:
\(m = \left\lfloor\dfrac{an+b}{c}\right\rfloor\)
那么

\[f(a, b, c, n) = \sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{\left[j < \left\lfloor\dfrac{ai+b}{c}\right\rfloor\right]} \]

我们有

\[\left\lfloor\dfrac{ai+b}{c}\right\rfloor = \left\lceil\dfrac{ai+b+1}{c}\right\rceil-1 \]

于是转化为

\[f(a, b, c, n) = \sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{\left[j + 1 < \left\lceil\dfrac{ai+b+1}{c}\right\rceil\right]} \]

\[= \sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{\left[j + 1 < \dfrac{ai+b+1}{c}\right]} \]

\[= \sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{\left[\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor < i\right]} \]

\[= \sum\limits_{j=0}^{m-1}\sum\limits_{i=0}^n{\left[\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor < i\right]} \]

\[= \sum\limits_{j=0}^{m-1}\left(n-\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor\right) \]

\[= nm-f(c, c - b - 1, a, m - 1) \]

此时 \(a'=c, c'=a, a'>c'\) 又变成了上面的情况。

时间复杂度 \(\mathcal{O}(\log\min(a, c))\),类似欧几里得算法的证明。

同时,若 \(m = 0\),立即终止的话,复杂度会变为 \(\mathcal{O}(\log\min(a, c, n))\),证明参见 OIWiki

几何直观

相当于直线 \(y = \dfrac{ax+b}{c}\)\([0, n]\) 上的整点个数。推导过程可以看 OIWiki

例题

abc443g

转化一下:

\[(Ak+B)\bmod M > k \]

\[(Ak+B)\bmod M \ge k + 1 \]

\[(Ak+B)-M\left\lfloor\dfrac{Ak+B}{M}\right\rfloor\ge k+1 \]

\[\left\lfloor\dfrac{Ak+B}{M}\right\rfloor \le \left\lfloor\dfrac{(A-1)k+B-1}{M}\right\rfloor \]

由于

\[\left\lfloor\dfrac{Ak+B}{M}\right\rfloor - \left\lfloor\dfrac{(A-1)k+B-1}{M}\right\rfloor \in [0, 1] \cap\mathbb N \]

所以答案就是

\[N - \left(\sum\limits_{k=0}^{N-1}\left\lfloor\dfrac{Ak+B}{M}\right\rfloor - \left\lfloor\dfrac{(A-1)k+B-1}{M}\right\rfloor\right) \]

为了防止 \(B = 0\) 的特判,考虑把 \(N\) 加在里面,变成

\[\sum\limits_{k=0}^{N-1}\left(\left\lfloor\dfrac{(A-1)k+B-1+M}{M}\right\rfloor-\left\lfloor\dfrac{Ak+B}{M}\right\rfloor\right) \]

套一个类欧板子即可,时间复杂度 \(\mathcal{O}(T\log\min(N, M, A))\),代码中变量名有所不同。

【模板】类欧几里得算法

\[f(a, b, c, n) = \sum\limits_{i=0}^n\left\lfloor\dfrac{ai+b}{c}\right\rfloor, g(a, b, c, n) = \sum\limits_{i=0}^ni\left\lfloor\dfrac{ai+b}{c}\right\rfloor, h(a, b, c, n) = \sum\limits_{i=0}^n\left\lfloor\dfrac{ai+b}{c}\right\rfloor^2 \]

类似 \(f\) 的推导,我们有:

\[g(a, b, c, n) = g(a \bmod c, b \bmod c, c, n) + \left\lfloor\dfrac{a}{c}\right\rfloor\dfrac{n(n+1)(2n+1)}{6}+\left\lfloor\dfrac{b}{c}\right\rfloor\dfrac{n(n+1)}{2} \]

\[h(a, b, c, n) = h(a \bmod c, b \bmod c, c, n) + \left\lfloor\dfrac{a}{c}\right\rfloor^2\dfrac{n(n+1)(2n+1)}{6}+\left\lfloor\dfrac{b}{c}\right\rfloor^2(n+1)+ \left\lfloor\dfrac{a}{c}\right\rfloor \left\lfloor\dfrac{b}{c}\right\rfloor n(n+1)+2\left\lfloor\dfrac{b}{c}\right\rfloor f(a\bmod c, b\bmod c, c, n) + 2\left\lfloor\dfrac{a}{c}\right\rfloor g(a\bmod c, b\bmod c, c, n) \]

考虑 \(a < c, b < c\) 的情况:
对于和式

\[\sum\limits_{i=0}^n i^r\left\lfloor\dfrac{ai+b}{c}\right\rfloor^s \]

我们只需将求解 \(f\) 的过程中

\[\sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{\left[j < \left\lfloor\dfrac{ai+b}{c}\right\rfloor\right]} \]

这步,改为

\[\sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{i^r((j+1)^s-j^s)\left[j < \left\lfloor\dfrac{ai+b}{c}\right\rfloor\right]} \]

即可,之后类似推导。
对于 \(g\)

\[g(a, b, c, n)=\sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{i\left[j < \left\lfloor\dfrac{ai+b}{c}\right\rfloor\right]} \]

\[= \sum\limits_{j=0}^{m-1}\sum\limits_{i=0}^ni{\left[\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor < i\right]} \]

\[= \sum\limits_{j=0}^{m-1}\sum\limits_{i=0}^n\dfrac{1}{2}\left(n+\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor+1\right)\left(n-\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor\right) \]

\[=\dfrac{1}{2}mn(n+1)-\dfrac{1}{2}f(c, c - b - 1, a, m - 1) - \dfrac{1}{2}h(c, c - b - 1, a, m - 1) \]

对于 \(h\)

\[h(a, b, c, n)=\sum\limits_{i=0}^n\sum\limits_{j=0}^{m-1}{(2j+1)\left[j < \left\lfloor\dfrac{ai+b}{c}\right\rfloor\right]} \]

\[= \sum\limits_{j=0}^{m-1}(2j+1)(n-\left\lfloor\dfrac{cj+c-b-1}{a}\right\rfloor) \]

\[=nm^2-f(c, c - b - 1, a, m - 1) - 2g(c, c - b - 1, a, m - 1) \]

递归计算 \(f, g, h\) 即可,时间复杂度 \(\mathcal{O}(\log\min(a, c, n))\)

posted @ 2026-08-25 08:56  循环一号  阅读(5)  评论(0)    收藏  举报