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秒就算完了。

相关推荐
踏着七彩祥云的小丑9 小时前
pytest——Mark标记
开发语言·python·pytest
Dream of maid9 小时前
Python12(网络编程)
开发语言·网络·php
W230357657310 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
Y40900110 小时前
【多线程】线程安全(1)
java·开发语言·jvm
不爱吃炸鸡柳10 小时前
Python入门第一课:零基础认识Python + 环境搭建 + 基础语法精讲
开发语言·python
minji...10 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
Dxy123931021611 小时前
Python基于BERT的上下文纠错详解
开发语言·python·bert
SiYuanFeng12 小时前
Colab复现 NanoChat:从 Tokenizer(CPU)、Base Train(CPU) 到 SFT(GPU) 的完整踩坑实录
python·colab
wjs202412 小时前
JavaScript 语句
开发语言