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

求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. 每个元素对应一个一次多项式 (1 + a*x),系数数组为 [1, a]。
  2. 使用分治法将这些多项式分组相乘:每次把多项式列表分成左右两部分,递归计算每组的乘积,再用FFT将两组结果相乘。
  3. 由于我们只需要前k+1项的系数(更高次项对结果无影响),每次相乘后可以截断到前k+1项,减少计算量。
  4. 最终取乘积多项式中 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:58:05