自然数幂求和——第二类Strling数

本文探讨了利用第二类斯特林数简化幂求和计算的方法。斯特林数描述了将相同球放入不同盒子的方案数,文中给出了斯特林数的递推公式和一个关键性质。通过详细的数学推理,展示了如何将幂求和问题转化为斯特林数的组合表达。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个问题似乎有很多种求法,但感觉上第二类Strling数的做法是最方便的。


问题

求下面这个式子:
∑ i = 0 n i k \sum_{i=0}^n i^k i=0nik
n n n的范围可以很大。


第二类Strling数

第二类Strling数记作 S ( n , m ) S(n,m) S(n,m) S n m S_n^m Snm
定义: n n n个相同的球放在 m m m个不同的箱子里的方案数(其中的每一个箱子至少有一个球)。
很容易推出一个式子: S n m = S n − 1 m − 1 + m S n − 1 m S_n^m=S_{n-1}^{m-1}+mS_{n-1}^m Snm=Sn1m1+mSn1m。不解释。
有个通项公式,但是我不会推……不过在处理这个问题的时候用不着。


一个性质

a k = ∑ i = 0 k S k i i ! C a i a^k=\sum_{i=0}^kS_k^i i! C_a^i ak=i=0kSkii!Cai
如果直接理性地证明可能不容易,所以在这里通过它的定义来推理一下:
对于等式左边,相当于 k k k个不同的球放在 a a a个不同的箱子里。
对于等式右边,先枚举非空箱子的个数, S k i S_k^i Ski表示 k k k个不同的球放在 i i i个相同的箱子里。乘上 i ! i! i!相当于放在不同的箱子里,再乘上非空箱子的选法 C a i C_a^i Cai
当然这条式子也可以化成:
∑ i = 0 k S k i ∏ j = a − i + 1 a j \sum_{i=0}^kS_k^i \prod_{j=a-i+1}^a j i=0kSkij=ai+1aj


推理

先把结论放在前面:
∑ i = 0 n i k = ∑ i = 0 k S k i ∏ j = n − i + 1 n + 1 j i + 1 \sum_{i=0}^n i^k=\sum_{i=0}^k\frac{S_k^i\prod_{j=n-i+1}^{n+1}j}{i+1} i=0nik=i=0ki+1Skij=ni+1n+1j
证明如下:
∑ i = 0 n i k = ∑ a = 0 n ∑ i = 0 k S k i i ! C a i = ∑ i = 0 k S k i i ! ∑ a = 0 n C a i \sum_{i=0}^n i^k \\ =\sum_{a=0}^n\sum_{i=0}^kS_k^i i! C_a^i \\ =\sum_{i=0}^kS_k^i i!\sum_{a=0}^nC_a^i i=0nik=a=0ni=0kSkii!Cai=i=0kSkii!a=0nCai
因为 a &lt; i a&lt;i a<i C a i = 0 C_a^i=0 Cai=0,所以
= ∑ i = 0 k S k i i ! ∑ a = i n C a i =\sum_{i=0}^kS_k^i i!\sum_{a=i}^nC_a^i =i=0kSkii!a=inCai
C m n = C m − 1 n − 1 + C m − 1 n C_m^n =C_{m-1}^{n-1}+C_{m-1}^n Cmn=Cm1n1+Cm1n
∑ a = i n C a i = C i i + C i + 1 i + ⋯ + C n i = C i i + 1 + C i i + C i + 1 i + ⋯ + C n i = C i + 1 i + 1 + C i + 1 i + ⋯ + C n i ⋯ = C n + 1 i + 1 \sum_{a=i}^nC_a^i=C_i^i+C_{i+1}^i+\cdots +C_n^i \\ =C_i^{i+1}+C_i^i+C_{i+1}^i+\cdots +C_n^i \\ =C_{i+1}^{i+1}+C_{i+1}^i+\cdots +C_n^i \\ \cdots \\ =C_{n+1}^{i+1} a=inCai=Cii+Ci+1i++Cni=Cii+1+Cii+Ci+1i++Cni=Ci+1i+1+Ci+1i++Cni=Cn+1i+1
所以原式又可以化成下面这样:
= ∑ i = 0 k S k i i ! C n + 1 i + 1 = ∑ i = 0 k S k i ∏ j = n − i + 1 n + 1 j i + 1 =\sum_{i=0}^kS_k^i i!C_{n+1}^{i+1} \\ =\sum_{i=0}^k\frac{S_k^i\prod_{j=n-i+1}^{n+1}j}{i+1} =i=0kSkii!Cn+1i+1=i=0ki+1Skij=ni+1n+1j
这样式子就推完了。

### 关于Java中使用DFS进行字划分 #### 使用DFS解决字划分问题的核心概念 在处理涉及组合优化的问题时,深度优先搜索(DFS)是一种常用的方法。对于特定的字划分问题,比如将一组字划分为若干个满足一定条件的小集合,可以采用DFS来遍历所有可能的情况并找到符合条件的结果。 当涉及到具体的应用场景如题目描述中的情况——即把`1,2,...,n`这n个自然数分成两部分使得这两部分具有相同的和、平方和以及立方和时,可以通过构建一棵决策树来进行探索[^4]。每一步选择是否将当前考察到的元素加入第一个子集中还是第二个子集中,并通过递归的方式继续考虑下一个位置上的元素直到完成整个序列的选择过程为止。 为了提高效率,在实际编码过程中还需要引入一些剪枝策略以减少不必要的计算量: - **提前终止**:一旦发现某一分支无法达到目标,则立即停止对该分支更深层次节点的访问; - **记忆化存储**:记录已经遇到过的状态及其对应结果,避免重复运算; 下面给出一段基于上述原理编写的用于解答此类问题的Java代码片段作为参考: ```java import java.util.*; public class NumberPartition { private static boolean[] used; private static int sumA = 0; // 子集 A 的元素之和 private static long squareSumA = 0L; // 子集 A 的元素平方之后再求和 private static long cubeSumA = 0L; // 子集 A 的元素三次方之后再求和 public static void main(String[] args){ Scanner scanner=new Scanner(System.in); List<Integer> numbers= new ArrayList<>(); for(int i=1;i<=16;i++){ numbers.add(i); } used = new boolean[numbers.size()]; dfs(numbers, 0); System.out.println("No solution found."); } private static void dfs(List<Integer> nums,int index){ if(index==nums.size()){ if(check(nums)){ printResult(); System.exit(0); // 找到了合适的分割方案就退出程序 }else{ return ; } } // 尝试不放入任何集合 dfs(nums,index+1); // 放入集合A used[index]=true; Integer num = nums.get(index); sumA +=num; squareSumA+=Math.pow(num,2); cubeSumA+=Math.pow(num,3); dfs(nums,index+1); // 回溯操作 sumA -=num; squareSumA-=Math.pow(num,2); cubeSumA-=Math.pow(num,3); used[index]=false; } /** * 检查目前形成的两个子集是否满足三个约束条件 */ private static boolean check(List<Integer> nums){ double halfSum=(double)(sumOfNums(nums)/2d); double halfSquareSum=(squareSumOfNums(nums))/2d; double halfCubeSum=(cubeSumOfNums(nums))/2d; return Math.abs(sumA-halfSum)<1e-9 && Math.abs(squareSumA-halfSquareSum)<1e-9 && Math.abs(cubeSumA-halfCubeSum)<1e-9; } /** * 计算列表内全部值加起来后的总和 */ private static int sumOfNums(List<Integer> list){ return (int)list.stream().mapToInt(Integer::intValue).sum(); } /** * 计算列表内全部值各自取平方后再累加得到的结果 */ private static double squareSumOfNums(List<Integer> list){ return list.stream().mapToDouble(x->Math.pow(x.intValue(),2)).sum(); } /** * 计算列表内全部值各自取立方后再累加得到的结果 */ private static double cubeSumOfNums(List<Integer> list){ return list.stream().mapToDouble(x->Math.pow(x.intValue(),3)).sum(); } /** * 输出最终结果 */ private static void printResult(){ StringBuilder sbA =new StringBuilder("["); StringBuilder sbB =new StringBuilder("["); for(int i=0 ;i<used.length ;++i){ if(!used[i]){ sbA.append((i+1)+", "); }else{ sbB.append((i+1)+", "); } } String resultA=sbA.substring(0,sbA.length()-2)+"]"; String resultB=sbB.substring(0,sbB.length()-2)+"]"; System.out.printf("Set A:%s\nSet B:%s\n",resultA,resultB); } } ``` 这段代码实现了基本框架下的DFS逻辑,其中包含了必要的辅助函用来验证所选路径是否符合要求。此外还加入了简单的输入读取功能以便测试不同的据实例。需要注意的是这里假设输入范围固定为前16个正整,因此可以根据实际情况调整这部分内容。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值