133. 循环单位非因子(Repunit Nonfactors)

完全由数字 1 组成的数称为循环单位(repunit)。定义 \(R(k)\) 为长度为 \(k\) 的循环单位;例如,\(R(6)=111111\)

考虑形如 \(R(10^n)\) 的循环单位。

虽然 \(R(10)\)\(R(100)\)\(R(1000)\) 都不能被 \(17\) 整除,但 \(R(10000)\) 能被 \(17\) 整除。而对于 \(19\),无论 \(n\) 取何值,\(R(10^n)\) 都不能被 \(19\) 整除。事实上,值得注意的是,\(11\)\(17\)\(41\)\(73\) 是一百以内仅有的四个能成为 \(R(10^n)\) 因子的质数。

求所有小于十万且永远不能成为 \(R(10^n)\) 因子的质数之和。

分析:本题的核心是判断某个质数 \(p\) 能否整除 \(R(10^n)\)。由 \(R(k)=\frac{10^k-1}{9}\) 可得,对于 \(p\neq 3\)\(p\mid R(k)\) 当且仅当 \(10^k\equiv 1\pmod p\)。引入 \(A(p)=\operatorname{ord}_p(10)\)\(10\)\(p\) 的乘法阶,问题转化为:\(A(p)\mid 10^n=2^n\cdot5^n\) 是否有解。这意味着 \(A(p)\) 的质因子必须全部属于 \(\{2,5\}\)。利用 \(A(p)\mid(p-1)\),只需提取 \(p-1\) 中因子 \(2\)\(5\) 的幂次构成 \(M\),再检查 \(10^M\equiv 1\pmod p\) 即可。对 \(p=2,3,5\) 需要单独处理。

一、数学背景

循环单位 \(R(k)\) 定义为 \(R(k)=\frac{10^k-1}{9}\)。对于质数 \(p\),欲知是否存在 \(n\) 使得 \(p\mid R(10^n)\),分两种情况讨论。

\(p\neq 3\) 的情形:此时 \(\gcd(9,p)=1\)\(9\) 在模 \(p\) 下可逆,因此

$$p\mid R(k)\iff \frac{10^k-1}{9}\equiv0\pmod p\iff 10^k\equiv1\pmod p.$$

\(A(p)=\operatorname{ord}_p(10)\)\(10\)\(p\) 的乘法阶,即满足 \(10^d\equiv1\pmod p\) 的最小正整数 \(d\)。由费马小定理,\(A(p)\mid(p-1)\)。于是

$$p\mid R(10^n)\iff 10^{10^n}\equiv1\pmod p\iff A(p)\mid 10^n=2^n\cdot5^n.$$

因此 \(A(p)\mid 10^n\) 成立当且仅当 \(A(p)\) 的所有质因子均来自 \(\{2,5\}\)

\(p=3\) 的情形:此时 \(9\)\(3\) 不互质,等价的 \(10^k\equiv1\pmod3\) 不成立。直接计算:\(10\equiv1\pmod3\)\(R(k)=\sum_{i=0}^{k-1}10^i\equiv\sum_{i=0}^{k-1}1=k\pmod3\)。当 \(k=10^n\) 时,\(k\equiv1\pmod3\),故 \(R(10^n)\equiv1\not\equiv0\pmod3\)。因此 \(p=3\) 永远不整除 \(R(10^n)\)

\(p=2,5\) 的情形\(\gcd(10,p)\neq1\)\(10^k\not\equiv1\pmod p\) 恒成立。由 \(R(k)\) 的奇偶性和末位数字亦可知 \(p=2,5\) 永远不整除任何 repunit。

判定方法:对 \(p\neq3\),设 \(v_2,v_5\) 分别为 \(p-1\) 中因子 \(2\)\(5\) 的幂次,令 \(M=2^{v_2}\cdot5^{v_5}\)。则

$$A(p)\text{ 仅含因子 }2,5\iff A(p)\mid M\iff 10^M\equiv1\pmod p.$$

\(10^M\equiv1\pmod p\),则 \(p\) 可整除某个 \(R(10^n)\);否则 \(p\) 永远不能。

二、算法设计

对于小于 \(10^5\) 的所有质数 \(p\)

筛法与判定均可在极短时间内完成。

三、复杂度分析

四、代码实现与说明

"""
Project Euler Problem 133: Repunit Nonfactors

Find the sum of all primes below 100,000 that will never be a factor of R(10^n),
where R(k) = (10^k - 1) / 9 is the repunit of length k.
"""

from math import isqrt


def sieve_primes(limit: int) -> list[int]:
    """Return all primes below `limit` using the Sieve of Eratosthenes."""
    is_prime = [True] * limit
    is_prime[0] = is_prime[1] = False
    for i in range(2, isqrt(limit) + 1):
        if is_prime[i]:
            step = i
            start = i * i
            is_prime[start:limit:step] = [False] * ((limit - start - 1) // step + 1)
    return [i for i, p in enumerate(is_prime) if p]


def can_be_factor(p: int) -> bool:
    """
    Return True if prime p can divide R(10^n) for some integer n >= 0.

    For p == 3, the formula (10^k-1)/9 is not equivalent to 10^k \equiv 1 (mod 3)
    because 9 is not invertible mod 3. R(10^n) \equiv 1 (mod 3) always.
    """
    if p == 3:
        return False

    t = p - 1
    m = 1
    while t % 2 == 0:
        t //= 2
        m *= 2
    while t % 5 == 0:
        t //= 5
        m *= 5

    return pow(10, m, p) == 1


def solve(limit: int = 100000) -> int:
    """Return the sum of all primes below `limit` that never divide R(10^n)."""
    primes = sieve_primes(limit)
    total = 0
    for p in primes:
        if not can_be_factor(p):
            total += p
    return total


if __name__ == "__main__":
    limit = 100000
    result = solve(limit)
    print(result)

代码说明(按执行顺序):

导入与常量

sieve_primes

can_be_factor

solve

main 区块