所有长度为 k 的子数组的元素的乘积之和
Posted
技术标签:
【中文标题】所有长度为 k 的子数组的元素的乘积之和【英文标题】:Sum of products of elements of all subarrays of length k 【发布时间】:2016-01-01 23:58:20 【问题描述】:给出一个长度为 n 的数组。求子数组元素的乘积之和。
说明
数组 A = [2, 3, 4],长度为 3。
子数组长度2 = [2,3], [3,4], [2,4]
[2, 3] = 6
中元素的乘积[3, 4] = 12
中元素的乘积[2, 4] = 8
中元素的乘积长度为2 = 6+12+8 = 26的子数组的总和
同样,对于长度 3,Sum = 24
因为,对于更高长度的子数组,乘积可以更大,以模1000000007计算。
对于所有可能长度的子数组,即 1、2、3、......、n,找到这些和的有效方法是什么,其中 n 是数组的长度.
【问题讨论】:
是针对所有子数组还是只针对长度为2的子数组? 对所有可能长度为 1、2、3、......、n 的子数组计算总和。 限制n
和k
?
@MetaD 真可惜,因为 2 真的很简单 :)(n
加法,n
减法和 n
乘法)
n 和 k 可以达到 1000。
【参考方案1】:
有一个比较简单的方法:
构造术语(1 + A[i] * x)
的乘积:
P = (1 + A[0] * x) * (1 + A[1] * x) * (1 + A[2] * x)...*(1 + A[n-1] * x)
如果我们打开括号,那么我们将得到多项式
P = 1 + B[1] * x + B[2] * x^2 + ... + B[n] * x^n
第 K 个系数 B[k] 等于长度为 K 的集合的乘积之和 - 例如,B[n] = A[0]*A[1]*A[2]*..A[n-1], B[2] = A[0]*A[1] + A[0]*A[2] + ... + A[n-2]*A[n-1]
等等。
所以要找到所有可能集合的乘积之和,我们必须找到 x = 1 的多项式 P 的值,然后减去 1 以删除前导第 0 项。如果我们不想考虑单元素集,则减去 B1 = A[i] 的总和。
例子:
(1+2)(1+3)(1+4) = 60
60 - 1 = 59
59 - (2 + 3 + 4) = 50 = 24 + 26 - as your example shows
【讨论】:
我没有正确阅读问题。我认为我们需要分别为每个k
计算总和。这确实是正确答案。
如果我们想要的是所有非空子集上所有产品的总和,那么这应该是最有效的方法。如果我们想要部分和(即固定大小子集的部分),那么我看不出如何从中提取它们。【参考方案2】:
我们首先创建一个递归关系。令f(n, k)
为长度为n
的数组a
中长度为k
的子数组的所有乘积之和。基本情况很简单:
f(0, k) = 0 for all k
f(n, 0) = 1 for all n
第二条规则可能看起来有点违反直觉,但 1 是乘法的零元素。
现在我们找到了f(n+1, k)
的递归关系。我们想要所有大小为k
的子数组的乘积。这里有两种类型的子数组:包括a[n+1]
的子数组和不包括a[n+1]
的子数组。不包括a[n+1]
的总和正好是f(n, k)
。包括a[n+1]
在内的所有子数组恰好都是长度为k-1
的子数组加上a[n+1]
,所以它们的和积是a[n+1] * f(n, k-1)
。
这完成了我们的递归关系:
f(n, k) = 0 if n = 0
= 1 if k = 0
= f(n-1, k) + a[n] * f(n-1, k-1) otherwise
您可以使用一个巧妙的技巧来为您的动态编程使用非常有限的内存,因为函数 f
仅依赖于两个较早的值:
int[] compute(int[] a)
int N = a.length;
int[] f = int[N];
f[0] = 1;
for (int n = 1; n < N; n++)
for (int k = n; k >= 1; k--)
f[k] = (f[k] + a[n] * f[k-1]) % 1000000007;
return f;
【讨论】:
以上是关于所有长度为 k 的子数组的元素的乘积之和的主要内容,如果未能解决你的问题,请参考以下文章