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

目标

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

一个 子序列 的 能量 定义为子序列中 任意 两个元素的差值绝对值的 最小值 。

请你返回 nums 中长度 等于 k 的 所有 子序列的 能量和 。

由于答案可能会很大,将答案对 10^9 + 7 取余 后返回。

示例 1:

输入:nums = [1,2,3,4], k = 3
输出:4
解释:
nums 中总共有 4 个长度为 3 的子序列:[1,2,3] ,[1,3,4] ,[1,2,4] 和 [2,3,4] 。能量和为 |2 - 3| + |3 - 4| + |2 - 1| + |3 - 4| = 4 。

示例 2:

输入:nums = [2,2], k = 2
输出:0
解释:
nums 中唯一一个长度为 2 的子序列是 [2,2] 。能量和为 |2 - 2| = 0 。

示例 3:

输入:nums = [4,3,-1], k = 2
输出:10
解释:
nums 总共有 3 个长度为 2 的子序列:[4,3] ,[4,-1] 和 [3,-1] 。能量和为 |4 - 3| + |4 - (-1)| + |3 - (-1)| = 10 。

说明:

  • 2 <= n == nums.length <= 50
  • -10^8 <= nums[i] <= 10^8
  • 2 <= k <= n

思路

定义数组子序列的能量为子序列中任意两个元素差的绝对值的最小值,求数组长度为k的子序列的能量和。

首先思考,数组 nums 长度为n的子序列有多少?根据每一个元素是否在序列中可知有 2^n种可能。n 最大为50,2^50 = 1125899906842624。那么长度为k的子序列有多少? C(n,k) = n!/(k!(n-k)!),当 k=2 时,有 n(n-1)/2 个子序列。

只能考虑动态规划,自底向上地求解。我们可以使用状态压缩来表示子序列,当状态发生转移的时候该如何处理呢?假设我们知道了某k-1子序列的能量,那么再增加一个元素能量会如何变化?比如子序列1,3,6,10,能量为2,再加入一个元素9,能量变为1。还是需要遍历子序列的。那么我们可以根据压缩的状态仅遍历哪些bit位为1的元素。剩下的问题就是如何遍历子序列了。

看了提示,首先要排序,这样差值最小的就两两相邻。刚开始的时候我也在想能不能排序,虽然子序列要保持相对顺序,但本题考虑的是子序列中绝对值差最小的,与顺序无关。

// todo

代码

性能