You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

代码出现Time Limit Exceed问题:求解数位和为奇数的数字累加和

问题:计算1到n中数位和为奇数的数字之和(大n优化)

给定数字n(1 ≤ n < 1017),计算1到n中所有数位和为奇数的数字之和,结果取模109+7。例如输入13时,结果为1+3+5+7+9+10+12=47。
当前代码通过循环遍历每个数字判断数位和奇偶性并累加,但面对极大n时出现超时问题,请求分析代码问题并提供解决方案。
代码如下:

MOD = 1000000007
def getSum(number):
    total = 0
    while number > 0:
        total += number % 10
        number //= 10
    return (total % MOD) % 2

def sticker(number):
    stickerNeed = 0
    for oneDigit in range(1, number):
        if (getSum(oneDigit % MOD) == 1):
            stickerNeed += oneDigit
    return stickerNeed % MOD


number = int(input())
result = sticker(number)
print(result % MOD)

问题分析

  • 时间复杂度爆炸:代码采用暴力遍历1到n-1所有数字的方式,时间复杂度为O(n)。当n接近1017时,循环次数达到1017量级,根本不可能在合理时间内完成计算,必然触发超时。
  • 冗余计算叠加:getSum函数每次都要逐位计算数字的数位和,对于大数来说这会额外增加时间开销,进一步拖慢程序运行速度。

解决方案

要处理这种超大范围的数位统计问题,**数位动态规划(数位DP)**是最优选择。它通过逐位处理数字的每一位,维护状态来统计符合条件的数字数量与总和,时间复杂度仅为O(数字位数),完全适配n<10^17的场景。

实现代码

MOD = 10**9 + 7

def calculate_odd_sum(n):
    s = str(n)
    digit_count = len(s)
    
    # dp[pos][sum_parity][tight] = (count, total_sum)
    # pos: 当前处理到第几位(从0开始)
    # sum_parity: 前pos位的数位和奇偶性,0为偶,1为奇
    # tight: 当前数位是否受原数字n的限制(1受限制,0不受)
    # count: 该状态下符合条件的数字数量,total_sum: 这些数字的总和
    dp = [[[ (0, 0) for _ in range(2)] for __ in range(2)] for ___ in range(digit_count + 1)]
    dp[0][0][1] = (1, 0)  # 初始状态:0位数字,和为偶,受限制,数量1(代表空数字),总和0
    
    for pos in range(digit_count):
        current_max_digit = int(s[pos])
        for sum_parity in range(2):
            for tight in range(2):
                current_cnt, current_total = dp[pos][sum_parity][tight]
                if current_cnt == 0:
                    continue
                
                # 确定当前位可选取的最大数字
                upper_limit = current_max_digit if tight else 9
                for d in range(0, upper_limit + 1):
                    new_tight = 1 if (tight and d == upper_limit) else 0
                    new_sum_parity = (sum_parity + d) % 2
                    
                    # 计算当前位d对总和的贡献:d * 10^(剩余位数) * 当前状态的数字数量 + 已有总和
                    power = 10 ** (digit_count - pos - 1) % MOD
                    digit_contribution = (d * power) % MOD
                    new_total = (current_total + digit_contribution * current_cnt) % MOD
                    
                    # 更新dp状态
                    old_cnt, old_total = dp[pos+1][new_sum_parity][new_tight]
                    dp[pos+1][new_sum_parity][new_tight] = (
                        (old_cnt + current_cnt) % MOD,
                        (old_total + new_total) % MOD
                    )
    
    # 所有数位处理完成后,统计数位和为奇数的数字总和(包含0,但0的数位和为偶,不影响结果)
    total_odd = (dp[digit_count][1][0][1] + dp[digit_count][1][1][1]) % MOD
    return total_odd

n = int(input())
print(calculate_odd_sum(n) % MOD)

代码说明

  • 数位DP的核心是状态维护:dp[pos][sum_parity][tight]记录了处理到第pos位时,前pos位和的奇偶性为sum_parity、是否受原数字限制的情况下,符合条件的数字数量与总和。
  • 递推过程中,我们遍历每个数位的可能取值,更新状态并计算对应的总和贡献,彻底避免了暴力遍历所有数字的低效操作。
  • 对于17位的数字,计算量仅为10172*2=680次,完全不会出现超时问题。

内容的提问来源于stack exchange,提问作者zeliha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:21:00