162. 十六进制数(Hexadecimal Numbers)

在十六进制数系统中,数字使用 16 个不同的数码表示:

$$0,1,2,3,4,5,6,7,8,9,\mathrm A,\mathrm B,\mathrm C,\mathrm D,\mathrm E,\mathrm F.$$

十六进制数 \(\mathrm{AF}\) 在十进制中等于 \(10\times16+15=175\)

在 3 位十六进制数 \(10\mathrm A\)\(1\mathrm A0\)\(\mathrm A10\)\(\mathrm A01\) 中,数码 \(0\)\(1\)\(\mathrm A\) 全部出现。与十进制数的写法一样,我们书写十六进制数时没有前导零。

问:最多十六位的十六进制数中,有多少个数同时包含数码 \(0\)\(1\)\(\mathrm A\) 至少各一次?答案以十六进制数形式给出。

(A, B, C, D, E 和 F 使用大写,不加任何标记十六进制的前缀或后缀,不加前导零。例如 1A3F,而不是 1a3f、0x1a3f、$1A3F、#1A3F 或 0000001A3F)

分析:对每个长度 \(k\)\(1\le k\le16\)),用容斥原理计算同时包含 \(0,1,\mathrm A\)\(k\) 位十六进制数个数。首位不能为 0(15 种选择),其余位各 16 种。对不含某数码的集合用容斥求和。

一、数学背景

\(D=\{0,1,\dots,9,\mathrm A,\dots,\mathrm F\}\)(16 个数码),\(D_1=D\setminus\{0\}\)(15 个,作首位数码)。

对长度为 \(k\) 的十六进制数,首位选自 \(D_1\),后 \(k-1\) 位选自 \(D\)。全集大小:

$$|\Omega| = 15\cdot 16^{k-1}$$

定义三个"不含"集合: - \(U_0\):不含数码 0 - \(U_1\):不含数码 1 - \(U_A\):不含数码 \(\mathrm A\)

目标计数为 \(|\Omega| - |U_0\cup U_1\cup U_A|\)。由容斥原理:

$$|U_0\cup U_1\cup U_A| = \sum |U_i| - \sum |U_i\cap U_j| + |U_0\cap U_1\cap U_A|$$

逐项计算(首位限制 \(D_1\) 与其余位限制 \(D\) 不同):

集合 首位选择数 其余位选择数 大小
\(U_0\) \(15\) \(15^{k-1}\) \(15^k\)
\(U_1\) \(14\) \(15^{k-1}\) \(14\cdot15^{k-1}\)
\(U_A\) \(14\) \(15^{k-1}\) \(14\cdot15^{k-1}\)
\(U_0\cap U_1\) \(14\) \(14^{k-1}\) \(14^k\)
\(U_0\cap U_A\) \(14\) \(14^{k-1}\) \(14^k\)
\(U_1\cap U_A\) \(13\) \(14^{k-1}\) \(13\cdot14^{k-1}\)
\(U_0\cap U_1\cap U_A\) \(13\) \(13^{k-1}\) \(13^k\)

代入容斥公式得 \(N_k\) 通项:

$$N_k = 15\cdot16^{k-1} - 15^k - 28\cdot15^{k-1} + 2\cdot14^k + 13\cdot14^{k-1} - 13^k$$

其中 \(28\cdot15^{k-1} = 2\cdot14\cdot15^{k-1}\) 来自 \(U_1\)\(U_A\) 两项之和。

验证 \(k=3\)\(N_3=4\),对应题面给出的四个三数码(10A、1A0、A10、A01),正确。

二、算法设计

\(k=1\)\(16\) 求和 \(\sum N_k\),将结果用 Python 格式化为大写十六进制数输出。所有运算使用 Python 内置整数(无限精度),可直接计算 \(16^{16}\) 以下的幂。

三、复杂度分析

仅需 16 次迭代的简单算术,时间复杂度 \(O(1)\),远小于 60 秒限制。

四、代码实现与说明

"""
Project Euler Problem 162: Hexadecimal Numbers

Count hexadecimal numbers with at most 16 digits (no leading zeros)
that contain digits 0, 1, and A each at least once.
Output the answer as a hexadecimal number (uppercase, no prefix).
"""


def count_k(k: int) -> int:
    """Return the number of k-digit hex numbers containing 0, 1, A at least once."""
    if k < 1:
        return 0
    return (
        15 * 16 ** (k - 1)
        - 15 ** k
        - 28 * 15 ** (k - 1)
        + 2 * 14 ** k
        + 13 * 14 ** (k - 1)
        - 13 ** k
    )


def solve() -> int:
    """Sum counts for lengths 1 through 16 and return the total."""
    total = 0
    for k in range(1, 17):
        total += count_k(k)
    return total


if __name__ == "__main__":
    result = solve()
    print(f"{result:X}")

代码说明:

count_k

solve

输出