語法書 / AA 競程語法書 下冊 / 第十七單元 / 改變枚舉順序:A×B×C

17.7 改變枚舉順序:A×B×C

壓軸是 AtCoder ARC113 A - A*B*C:給 K \le 2 \times 10^5,數出有幾組正整數三元組 (A, B, C) 滿足 A \times B \times C \le K(順序不同算不同組)。例如 K = 2 的答案是 4(1,1,1)(1,1,2)(1,2,1)(2,1,1)

直覺做法:三重迴圈枚舉 (A, B, C) 逐組檢查——K^3 = 8 \times 10^{15} 次,10.1 三步驟一估就知道連想都不用想。

換個枚舉順序:只枚舉 ABC 用算的。固定 ABA \times B \le K)之後,C 能選 1, 2, \ldots, \left\lfloor \dfrac{K}{A \times B} \right\rfloor——幾種選法一條除法直接得出(17.2 的數學性質又立功),第三層迴圈整層消失:

完整程式碼

#include <iostream>
using namespace std;

int main() {
    int k;
    cin >> k;
    long long ans = 0;
    for (long long a = 1; a <= k; a++) {
        for (long long b = 1; a * b <= k; b++) {
            ans += k / (a * b);            // C 有 floor(K / (A*B)) 種選法
        }
    }
    cout << ans << '\n';
    return 0;
}

執行結果(輸入 2):

4

這樣要跑幾圈?內層對每個 A 最多跑 \dfrac{K}{A} 圈,總圈數是

\frac{K}{1} + \frac{K}{2} + \frac{K}{3} + \cdots + \frac{K}{K}

這串和大約是 K \times \log K 等級——又是 \log!(它就是喜歡在「除法、砍半、切塊」的場景冒出來。)本站實測 K = 2 \times 10^5 總共約 2.4 \times 10^6 圈、0.01 秒內跑完。從 8 \times 10^{15}2.4 \times 10^6——改變枚舉順序+一條除法,十億倍的差距。

為什麼那串和恰好是 K \log K 等級?完整的推導在 AA 競程的公開影片 Level 1 試聽課 03:以 ARC113 A 作為用數學方法計算時間複雜度的範例——這題正是 Level 1 開場的招牌例題,先解掉再看影片,收穫最大。