3082. 求出所有子序列的能量和

2024/03/24 leetcode 共 1568 字,约 5 分钟

title

problem link

给你一个长度为 n 的整数数组 nums 和一个 正 整数 k 。

一个整数数组的 能量 定义为和 等于 k 的子序列的数目。

请你返回 nums 中所有子序列的 能量和 。

由于答案可能很大,请你将它对 109 + 7 取余 后返回。

示例 1:

输入: nums = [1,2,3], k = 3

输出: 6

解释:

总共有 5 个能量不为 0 的子序列:

  • 子序列 [***1***,***2***,***3***] 有 2 个和为 3 的子序列:[1,2,***3\***] 和 [***1\***,***2\***,3] 。
  • 子序列 [***1***,2,***3***] 有 1 个和为 3 的子序列:[1,2,***3\***] 。
  • 子序列 [1,***2***,***3***] 有 1 个和为 3 的子序列:[1,2,***3\***] 。
  • 子序列 [***1***,***2***,3] 有 1 个和为 3 的子序列:[***1\***,***2\***,3] 。
  • 子序列 [1,2,***3***] 有 1 个和为 3 的子序列:[1,2,***3\***] 。

所以答案为 2 + 1 + 1 + 1 + 1 = 6 。

示例 2:

输入: nums = [2,3,3], k = 5

输出: 4

解释:

总共有 3 个能量不为 0 的子序列:

  • 子序列 [***2***,***3***,***3***] 有 2 个子序列和为 5 :[***2\***,3,***3\***] 和 [***2\***,***3\***,3] 。
  • 子序列 [***2***,3,***3***] 有 1 个子序列和为 5 :[***2\***,3,***3\***] 。
  • 子序列 [***2***,***3***,3] 有 1 个子序列和为 5 :[***2\***,***3\***,3] 。

所以答案为 2 + 1 + 1 = 4 。

示例 3:

输入: nums = [1,2,3], k = 7

输出: 0

解释:不存在和为 7 的子序列,所以 nums 的能量和为 0 。

提示:

  • 1 <= n <= 100
  • 1 <= nums[i] <= 104
  • 1 <= k <= 100

solution

动态规划,表示考虑前i 个物品,所选物品体积和是 j,选了 c 个物品的方案数。

这里不能用前i个物品,同时第i个结尾的用法。如果没有对第i个结尾有需要就可以不用,否则会复杂度再乘以个n。

时间复杂度O(nnk)

class Solution:
    def sumOfPower(self, nums: List[int], k: int) -> int:
        MOD = int(1e9 + 7)
        import functools
        @functools.lru_cache(None)
        def f(i, s, l):
            # print((i,s,l))
            if i == 0:
                if s == 0 and l == 0:
                    return 1
                return 0
            v = nums[i - 1]
            res = 0
            # select
            if s - v >= 0 and l - 1 >= 0:
                res += f(i - 1, s - v, l - 1)
            # not
            res += f(i - 1, s, l)
            res %= MOD
            return res

        n = len(nums)
        # dp = [[0 for _ in range(k + 1)] for _ in range(n + 1)]
        # dp[0][0] = 1
        # for i in range(n):
        #     v = nums[i]
        #     for l in range(n, 0, -1):
        #         for s in range(k, 0, -1):
        #             if s - v >= 0:
        #                 dp[l][s] += dp[l - 1][s - v]
        # p = 1
        # ans = 0
        # for l in range(len(nums), 0, -1):
        #     count = dp[l][k]
        #     ans += count * p
        #     p *= 2
        #     p %= MOD
        #     ans %= MOD
        # return ans
        #
        # n = len(nums)
        p = 1
        ans = 0
        for l in range(len(nums), 0, -1):
            count = f(n, k, l)
            ans += count * p
            p *= 2
            p %= MOD
            ans %= MOD
        f.cache_clear()
        return ans

Search

    Table of Contents