各位数字之和为 s 的 n 位正整数有多少个?

这是有条件限制的正整数有序拆分问题,没有直接的计算公式。

如果规模小,可以枚举。如果大到上百位,可以用动态规划算法。如果大到上千位,动态规划法也得几十分钟,甚至几个小时。规模更大,大到上万位的话,受时间和空间限制,PC 已无力完成了。


“插板法+容斥原理” 是个大杀器。

参考了 CSDN 网友 “西域狂猪” 的文章,核心算法见如下公式:
在这里插入图片描述
需要减去首位为 0 的情形,即:
total = sum( i = 0~n ) - sum( i = 0~n-1 )


Python 有内置的大整数和组合计算函数,测试了一下,效率胜过 Fortran。

Python 代码如:

# 1000位正整数,各位数字之和为5000,有多少个?
# szw_sh@163.com
# 2024-07-14

from math import comb
import time

def sum_expression(n, s, m):
    
  """
  计算满足特定条件的项的累加和。
  参数:
  n -- 正整数的位数
  s -- 各位数字之和
  m -- 各数字小于该值
  返回: 满足条件的项的累加和
  """
  total_sum = 0
  for i in range(n + 1):
    if i * m > s:
      break
    term = (-1)**i * comb(n-1+s-i*m, n-1) * comb(n, i)
    total_sum += term
  return total_sum

n = 1000
s = 5000
m = 10

start_time = time.time()
total = sum_expression(n, s, m) - sum_expression(n-1, s, m)
end_time = time.time()
time = (end_time - start_time) * 1000

print(f"total = {total}")
print(f"time = {time:.0f} ms")


n = 1000,s = 5000,m = 10 时,运行耗时 507 毫秒。

计算结果:

total = 10285365067195108279225142980141878600436775717079668098763107749084681963865663398549438382871357086343262593006829915422766021250213523036365720794008181853252571208894977792325007703100745052309162270431546632904405801249072129315390740993369189182722741184529959028657805877226409256723754071554845143402710377458469861704855510858930204077579300369143561806187085658687038624639772365001271352767972620393008430988939906039570647457525714932032736164841522324617879072246419422236156405366464153445733145564034044182972376371702400606659207050480816922601281434846851694581686209528756902423796651122212073205284566821880292636599595714274027420413877993217075979458903453123944101597589100389223674589656462816635288040086976653861613595937991672823392045555064175060116269398996825041632535493492592636186432758707578488603262994149040157870336864388850537821127957936706260836057978829775191634098139364843182377363956436912804227224405620901587681832910238503135057103703350309161710
time = 507 ms

附:在线编译运行的截图
在这里插入图片描述

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值