DeepSeek 辅助编写python程序求解欧拉计划932题:2025数

原题地址:https://pe-cn.github.io/932/

一开始让他自由发挥,结果写出来的程序是错的。

然后让他从穷举法开始编写,

python 复制代码
# coding=utf-8
def find_all_2025_numbers():
    results = []
    
    # 枚举所有可能的 a 和 b
    for a in range(1, 5000):
        for b in range(1, 5000):
            # 计算连接后的数
            # 先确定 b 的位数
            b_digits = len(str(b))
            N = a * (10 ** b_digits) + b
            
            # 检查是否为完全平方数
            s = a + b
            if N == s * s:
                results.append((N, a, b))
    
    # 按 N 排序并去重
    results = sorted(set(results), key=lambda x: x[0])
    
    # 输出结果
    print(f"{'N':<10} {'a':<10} {'b':<10} {'a+b':<10} (a+b)²")
    print("-" * 50)
    for N, a, b in results:
        s = a + b
        print(f"{N:<10} {a:<10} {b:<10} {s:<10} {s*s}")
    
    print(f"\n共找到 {len(results)} 个 2025 数")
    return results

if __name__ == "__main__":
    find_all_2025_numbers()

把输出反馈给他理解。

复制代码
n<=5000有如下规律:请分析总结
N          a          b          a+b        (a+b)²
--------------------------------------------------
81         8          1          9          81
2025       20         25         45         2025
3025       30         25         55         3025
88209      88         209        297        88209
494209     494        209        703        494209
4941729    494        1729       2223       4941729
7441984    744        1984       2728       7441984
24502500   2450       2500       4950       24502500
25502500   2550       2500       5050       25502500

上述穷举程序效率低,根据完全平方数的后几位找b,前几位找a的思路来重写,不做别的

终于编对了, 改进版如下:

根据完全平方数的性质,我来重写高效的程序:

python 复制代码
def solve_T16():
    n = 16
    total_sum = 0
    seen = set()
    
    # 枚举可能的位数 k (b的位数)
    for k in range(1, n):
        # 10^k 和 10^k - 1
        pow10_k = 10 ** k
        pow10_k_minus_1 = pow10_k - 1
        
        # b 的范围:k 位数
        min_b = 10 ** (k - 1)
        max_b = pow10_k - 1
        
        # 对于每个可能的 b,我们需要解方程:
        # N = s^2,且 N 的最后 k 位是 b
        # 即 s^2 ≡ b (mod 10^k)
        
        # 枚举可能的 s 模 10^k 的值
        # 实际上,我们需要 s^2 ≡ b (mod 10^k)
        # 可以通过枚举 s 模 10^k 来找到所有解
        
        # 对于给定的 b,我们需要找到所有 s 使得 s^2 ≡ b (mod 10^k)
        # 然后检查对应的 N 是否 ≤ 10^n
        
        # 更高效的方法:直接枚举 s 并检查 b 的位数条件
        # s 的范围:s^2 的位数 ≤ n,所以 s ≤ 10^(n/2)
        max_s = int(10 ** (n / 2)) + 1
        
        # 对于每个可能的 s 模 10^k 的余数,我们可以跳着枚举
        # 但更简单:枚举所有 s 并检查,因为 n=16 时 s 只有 10^8 个,但这对 Python 来说太大了
        
        # 改用数学方法:b = s(10^k - s)/(10^k - 1) 必须为整数
        # 所以 (10^k - 1) | s(10^k - s)
        
        # 枚举 s 模 10^k - 1 的倍数
        mod_val = pow10_k_minus_1
        max_s_val = max_s
        
        # 从最小的可能 s 开始
        s_start = 2  # s = a+b ≥ 2
        
        # 对于每个可能的 s,检查 b 是否为整数且为 k 位数
        for s in range(s_start, max_s_val + 1):
            # 计算 b = s(10^k - s)/(10^k - 1)
            numerator = s * (pow10_k - s)
            if numerator % pow10_k_minus_1 != 0:
                continue
            
            b = numerator // pow10_k_minus_1
            
            # 检查 b 是否为 k 位数
            if b < min_b or b > max_b:
                continue
            
            # 计算 a = s - b
            a = s - b
            if a <= 0:
                continue
            
            # 验证 N = a * 10^k + b = s^2
            N = a * pow10_k + b
            if N != s * s:
                continue
            
            # 检查 N 的位数是否 ≤ n
            if len(str(N)) > n:
                continue
            
            if N not in seen:
                seen.add(N)
                total_sum += N
                # print(f"N={N}, a={a}, b={b}, k={k}, s={s}")
    
    return total_sum

if __name__ == "__main__":
    result = solve_T16()
    print(f"T(16) = {result}")

这个程序的思路:

  1. 固定 b 的位数 k
  2. 直接枚举 s = a+b,因为 s 的范围相对较小(s ≤ 10^(n/2) = 10^8)
  3. 通过公式 b = s(10^k - s)/(10^k - 1) 计算 b
  4. 检查 b 是否为整数且为 k 位数
  5. 验证所有条件并累加结果

对于 n=16,s 最多有 10^8 个,但每个 k 都要遍历一次,总计算量约为 16 × 10^8 = 1.6e9,在 Python 中仍然较大,但比枚举 a,b 要高效很多。

实际运行速度有点慢。n=16,用了4分多钟。再让他优化。

你说得对,当 n=16 时,s 需要遍历到 10^8,这个数量级在 Python 中仍然太慢。我需要进一步优化。

关键优化点:利用 s(10^k - s) 必须被 10^k - 1 整除的条件,可以大幅减少枚举量。

python 复制代码
def solve_T16():
    n = 16
    total_sum = 0
    seen = set()
    
    # 枚举可能的位数 k (b的位数)
    for k in range(1, n):
        pow10_k = 10 ** k
        d = pow10_k - 1  # 10^k - 1
        
        # b 的范围:k 位数
        min_b = 10 ** (k - 1)
        max_b = pow10_k - 1
        
        # s 的最大值:s^2 的位数 ≤ n,所以 s ≤ 10^(n/2)
        max_s = int(10 ** (n / 2))
        
        # 我们需要 s(10^k - s) ≡ 0 (mod d)
        # 即 s(10^k - s) = s(pow10_k - s) ≡ 0 (mod d)
        # 由于 pow10_k ≡ 1 (mod d),所以 s(1 - s) ≡ 0 (mod d)
        # 即 s(s - 1) ≡ 0 (mod d)
        
        # 所以 d 必须整除 s(s-1)
        # 这意味着 s 要么是 d 的倍数,要么 s-1 是 d 的倍数
        # 或者更一般地,s 和 s-1 分别包含 d 的因子
        
        # 方法1:枚举 d 的倍数
        # s 必须是 d 的倍数,或者 s-1 是 d 的倍数
        # 但更精确地,我们需要考虑 d 的因子分解
        
        # 简单但有效的方法:枚举 d 的所有因子对
        # 对于每个因子 f 整除 d,设 s 是 f 的倍数,且 s-1 是 d/f 的倍数
        
        # 获取 d 的所有因子
        factors = []
        i = 1
        while i * i <= d:
            if d % i == 0:
                factors.append(i)
                if i != d // i:
                    factors.append(d // i)
            i += 1
        
        # 对于每对因子 (f, g) 满足 f * g = d
        # 我们需要 s 满足:f | s 且 g | (s-1)
        # 即 s ≡ 0 (mod f) 且 s ≡ 1 (mod g)
        
        # 使用中国剩余定理求解
        for f in factors:
            g = d // f
            
            # 解同余方程组:s ≡ 0 (mod f), s ≡ 1 (mod g)
            # 需要 gcd(f, g) = 1,否则可能无解
            from math import gcd
            if gcd(f, g) != 1:
                continue
            
            # 使用扩展欧几里得算法求解
            # 找到 x, y 使得 f*x + g*y = 1
            # 则 s = f * (1 - 0) * y? 实际上标准解是:
            # s = 0 * g * inv_g_mod_f + 1 * f * inv_f_mod_g
            # 但更简单:s = f * ((1 * inv_f_mod_g) % g)
            
            # 计算 f 模 g 的逆元
            inv_f_mod_g = pow(f, -1, g)
            s0 = f * inv_f_mod_g % (f * g)
            s0 = s0 % d
            
            # s0 是模 d 的一个解,所有解为 s = s0 + t*d
            # 枚举所有 s ≤ max_s
            if s0 == 0:
                s0 = d  # 避免 s=0
            s = s0
            while s <= max_s:
                # 检查这个 s 是否有效
                if s >= 2:  # s = a+b ≥ 2
                    # 计算 b = s(10^k - s)/d
                    numerator = s * (pow10_k - s)
                    if numerator % d == 0:
                        b = numerator // d
                        
                        # 检查 b 是否为 k 位数
                        if min_b <= b <= max_b:
                            a = s - b
                            if a > 0:
                                N = a * pow10_k + b
                                if len(str(N)) <= n and N not in seen:
                                    seen.add(N)
                                    total_sum += N
                
                s += d
            
            # 同样处理 s ≡ 1 (mod f), s ≡ 0 (mod g) 的情况
            # 交换 f 和 g 的角色
            inv_g_mod_f = pow(g, -1, f)
            s1 = g * inv_g_mod_f % (f * g)
            s1 = s1 % d
            if s1 == 0:
                s1 = d
            s = s1
            while s <= max_s:
                if s >= 2:
                    numerator = s * (pow10_k - s)
                    if numerator % d == 0:
                        b = numerator // d
                        if min_b <= b <= max_b:
                            a = s - b
                            if a > 0:
                                N = a * pow10_k + b
                                if len(str(N)) <= n and N not in seen:
                                    seen.add(N)
                                    total_sum += N
                s += d
    
    return total_sum

if __name__ == "__main__":
    result = solve_T16()
    print(f"T(16) = {result}")

这个优化的关键点:

  1. 利用同余关系 :从 s(10^k - s) ≡ 0 (mod d)10^k ≡ 1 (mod d) 推导出 s(s-1) ≡ 0 (mod d)

  2. 因子分解:d 的每个因子对 (f, g) 满足 f × g = d,对应两种情况:

    • f | s 且 g | (s-1)
    • g | s 且 f | (s-1)
  3. 中国剩余定理:解同余方程组得到 s 模 d 的解,然后每次增加 d 枚举所有可能的 s

这样枚举量从 O(10^8) 降低到 O(因子个数 × (max_s / d)),对于大多数 k,d 很大,枚举量很小。

这个版本n=16只用18秒就算完了。

相关推荐
2401_833197732 小时前
嵌入式C++电源管理
开发语言·c++·算法
ms_27_data_develop2 小时前
Java——集合
java·开发语言
灰色小旋风2 小时前
力扣22 括号生成(C++)
开发语言·数据结构·c++·算法·leetcode
2501_924952692 小时前
模板编译期哈希计算
开发语言·c++·算法
xiaoye-duck2 小时前
C++ STL map 系列深度解析:从底层原理、核心接口到实战场景
开发语言·c++·stl
2201_758642642 小时前
嵌入式C++开发注意事项
开发语言·c++·算法
七夜zippoe2 小时前
WebAssembly与Python:在浏览器中运行Python
开发语言·python·wasm·webassembly·pyscript
m0_662577972 小时前
自动化与脚本
jvm·数据库·python
小杍随笔2 小时前
【Rust 语言编程知识与应用:同步机制详解】
开发语言·算法·rust