求n元集合至多k元子集乘积和,寻求亚指数时间复杂度解法
解法思路与伪代码
这个问题的核心是计算前k阶初等对称多项式的和——也就是所有大小为1到k的子集的乘积之和。下面给你两种高效的解法,分别适用于不同的场景:
一、数学原理铺垫
假设集合元素为 a₁, a₂, ..., aₙ,我们构造多项式:
$$P(x) = (1+a₁x)(1+a₂x)...(1+aₙx)$$
展开后,x^m 的系数就是所有大小为m的子集的乘积之和(也就是m阶初等对称多项式)。我们要求的结果就是 P(x) 中 x¹ 到 xᵏ 的系数之和。
二、动态规划解法(适合k较小的场景)
当k远小于n时,动态规划是最直接且高效的选择,时间复杂度为 O(nk),实现简单,没有浮点误差。
思路
- 定义
dp[j]表示从已处理的元素中选j个的乘积之和,初始时dp[0] = 1(空集的乘积为1),dp[1..k] = 0。 - 遍历每个元素
a,从后往前更新dp数组(避免重复计算):对于每个j从k到1,dp[j] += dp[j-1] * a。 - 最终结果就是
sum(dp[1..k])。
伪代码
def subset_product_sum_dp(arr, k): # 初始化dp数组:dp[j]表示选j个元素的乘积之和 dp = [0] * (k + 1) dp[0] = 1 # 空集乘积为1 for a in arr: # 从后往前更新,防止重复使用当前元素 for j in range(k, 0, -1): dp[j] += dp[j-1] * a # 求和所有1到k阶的对称多项式 return sum(dp[1:k+1])
示例验证
对于集合 {1,2,3,4,5},k=2:
- 处理完所有元素后,
dp[1] = 1+2+3+4+5=15,dp[2] = 1*2+1*3+1*4+1*5+2*3+2*4+2*5+3*4+3*5+4*5=85 - 结果为
15+85=100,与正确值一致。
三、FFT分治法(适合k接近n的场景)
当k和n差不多大时,O(nk) 的动态规划会达到 O(n²) 复杂度,这时候用分治法结合FFT加速多项式乘法,时间复杂度可以降到 O(n log²n),更适合大规模输入。
思路
- 每个元素对应一个一次多项式
(1 + a*x),系数数组为[1, a]。 - 使用分治法将这些多项式分组相乘:每次把多项式列表分成左右两部分,递归计算每组的乘积,再用FFT将两组结果相乘。
- 由于我们只需要前k+1项的系数(更高次项对结果无影响),每次相乘后可以截断到前k+1项,减少计算量。
- 最终取乘积多项式中
x¹到xᵏ的系数之和作为结果。
伪代码
import numpy as np def subset_product_sum_fft(arr, k): n = len(arr) def divide_conquer(l, r): if l == r: # 单个元素对应的多项式,截断到k+1项 poly = [1, arr[l]] return poly[:k+1] if k >=1 else [1] mid = (l + r) // 2 left_poly = divide_conquer(l, mid) right_poly = divide_conquer(mid+1, r) # 用FFT计算多项式乘积并截断到k+1项 product_poly = multiply_fft(left_poly, right_poly, k+1) return product_poly full_poly = divide_conquer(0, n-1) return sum(full_poly[1:k+1]) def multiply_fft(a, b, max_degree): len_a = len(a) len_b = len(b) # 计算FFT所需的最小2的幂次长度 fft_len = 1 while fft_len < len_a + len_b -1: fft_len <<= 1 # 补零并进行FFT a_fft = np.fft.fft(a + [0]*(fft_len - len_a)) b_fft = np.fft.fft(b + [0]*(fft_len - len_b)) # 频域相乘后逆FFT c_fft = a_fft * b_fft c = np.fft.ifft(c_fft) # 取实部并四舍五入(消除浮点误差) c = [round(x.real) for x in c] # 截断到指定最高次项 return c[:max_degree]
注意事项
- FFT会引入浮点误差,所以需要对结果进行四舍五入处理。
- 当k=0时,结果为0(因为没有非空子集),伪代码中已经做了简单处理。
内容的提问来源于stack exchange,提问作者MathCoder97
相关产品推荐
相关产品推荐

