141. 平方累进数(Square Progressive Numbers)

给定正整数 \(n\),除以 \(d\) 得到商 \(q\) 和余数 \(r\)\(d\)\(q\)\(r\) 是一个等比数列中连续的三项,顺序不限。 我们称这样的数 \(n\) 为"累进数"(progressive)。

有些累进数恰好也是完全平方数,如 \(9\)\(10404 = 102^2\)。 所有小于十万的累进完全平方数之和为 \(124657\)

求所有小于一万亿(\(10^{12}\))的累进完全平方数之和。

一、数学背景

设三个等比数列项(从大到小排列)为 \(T_1 > T_2 > T_3\),公比为 \(k = \frac{p}{q}\)\(p>q\)\(\gcd(p,q)=1\))。

等比三项可表示为:

$$T_1 = a p^2, \quad T_2 = a p q, \quad T_3 = a q^2$$

其中 \(a \geq 1\)

给定 \((d, q_{out}, r) = (T_1, T_2, T_3)\) 的某个排列,且约束 \(r < d\)(余数小于除数)。

遍历所有 \(6\) 种排列:

$$ \begin{aligned} &(d,q,r) = (T_2, T_1, T_3): & n &= T_2 T_1 + T_3 = a^2 p^3 q + a q^2 = a q (a p^3 + q) \quad &\text{(公式A)}\\ &(d,q,r) = (T_3, T_2, T_1): & n &= T_3 T_2 + T_1 = a^2 p^3 q + a q^2 = a q (a p^3 + q) \quad &\text{(与A相同)}\\ &(d,q,r) = (T_3, T_1, T_2): & n &= T_3 T_1 + T_2 = a^2 p^2 q^2 + a p q = a p q (a p q + 1) \quad &\text{(公式B)} \end{aligned} $$

其余三种排列因 \(r > d\) 不成立。

公式B中 \(n = k(k+1)\),其中 \(k = a p q\)。由于 \(\gcd(k,k+1)=1\),两者必须都是完全平方数才能使其乘积为完全平方数。设 \(k = u^2\)\(k+1 = v^2\),则 \(v^2 - u^2 = 1\),即 \((v-u)(v+u) = 1\),仅有零解 \(u=0\)。故公式B无有效解。

因此问题归结为:寻找 \(n = a q(a p^3 + q)\) 为完全平方数,其中 \(p>q\)\(\gcd(p,q)=1\)\(a \geq 1\)

二、算法设计

采用三重循环枚举 \(p\)\(q\)\(a\)

每轮检查 \(n\) 是否为完全平方数,若是则加入集合。最后求集合元素之和。

去重考虑

同一个累进完全平方数理论上可能有多种 \((p,q,a)\) 表示。使用 set 确保不重复计算。

三、复杂度分析

四、代码实现与说明

整体结构

import math

def sum_progressive_squares(limit: int) -> int:
    seen = set()
    p = 2
    while True:
        p3 = p * p * p
        if p3 >= limit:
            break
        for q in range(1, p):
            if math.gcd(p, q) != 1:
                continue
            a = 1
            while True:
                n = a * q * (a * p3 + q)
                if n >= limit:
                    break
                s = math.isqrt(n)
                if s * s == n:
                    seen.add(n)
                a += 1
        p += 1
    return sum(seen)

关键细节说明