類歐幾里得算法

定義

這個算法用於求一條直線下整點個數,我們定義

\[ F(a, b, c, n) = \sum_{i = 0}^{n} \lfloor \frac{ai + b}{c} \rfloor \]

其他幾個乘係數的擴展不想學了TAT

推導

\(a \ge c\)\(b \ge c\)

\(a \ge c\)\(b \ge c\) 時,我們考慮把分子對 \(c\) 的商和餘數分別提出來,那麼有

\[ \begin{aligned} F(a, b, c, n) &= \sum_{i = 0}^{n} ((\lfloor \frac{(a \bmod c)i + (b \bmod c)}{c} \rfloor) i + \lfloor \frac ac \rfloor i + \lfloor \frac bc\rfloor)\\ &= F(a \bmod c, b \bmod c, c, n) + \frac{n(n + 1)}{2} \lfloor \frac ac \rfloor + (n + 1) \lfloor \frac bc \rfloor \end{aligned} \]

\(a < c\)\(b < c\)

\(a < c\)\(b < c\) 時,用幾何意義轉化爲一條直線與 \(x\)\(y\) 軸以及 \(x = n\) 圍成直角梯形內的整點個數。

設上界 \(\displaystyle m = \lfloor \frac{an + b}{c} \rfloor\) ,那麼我們考慮拆式子

\[ \begin{aligned} F(a, b, c, n) &= \sum_{i = 0}^n \sum_{j = 1}^m [\lfloor \frac{ai + b}{c} \rfloor \ge j] \\ &= \sum_{i = 0}^n \sum_{j = 0}^{m - 1} [\lfloor \frac{ai + b}{c} \rfloor \ge j + 1] \\ &= \sum_{i = 0}^n \sum_{j = 0}^{m - 1} [(\frac{ai + b}{c}) \ge j + 1]\\ &= \sum_{i = 0}^n \sum_{j = 0}^{m - 1} [ai \ge jc + c - b]\\ &= \sum_{i = 0}^n \sum_{j = 0}^{m - 1} [i \ge \frac{jc + c - b}{a}]\\ \end{aligned} \]

很多地方都可以舍掉取整,因爲整數和分數比較大小(考慮等於)的時候可以忽略下取整。

考慮分子減 \(1\) 換成 \(>\) 並交換和式:

\[ \begin{aligned} F(a, b, c, n) &= \sum_{i = 0}^n \sum_{j = 0}^{m - 1} [i > \frac{jc + c - b - 1}{a}]\\ &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [i > \frac{jc + c - b - 1}{a}]\\ &= \sum_{j = 0}^{m - 1} (n - \frac{jc + c - b - 1}{a})\\ &= nm - \sum_{j = 0}^{m - 1} \frac{jc + c - b - 1}{a}\\ &= nm - F(c, c - b - 1, a, m - 1) \end{aligned} \]

然後我們就可以遞歸處理了。

複雜度證明

我們只觀察 \(ac\) 兩位,如果 \(a > c\) 那麼 \(a \bmod c\) ,否則交換 \(ac\)

那麼複雜度其實和擴展歐幾里得算法是一樣的 \(\mathcal O(\log n)\)

代碼

\(f\) 還是比較短的。

ll f(ll a, ll b, ll c, ll n) {
    if (!a) return b / c * (n + 1);
    if (a >= c || b >= c)
        return f(a % c, b % c, c, n) + (a / c) * n * (n + 1) / 2 + (b / c) * (n + 1);
    ll m = (a * n + b) / c;
    return n * m - f(c, c - b - 1, a, m - 1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章