当前位置: 首页> 文旅> 美景 > 01背包+枚举,

01背包+枚举,

时间:2025/7/12 6:58:44来源:https://blog.csdn.net/EQUINOX1/article/details/140633879 浏览次数:0次

一、题目

1、题目描述

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

一个 

子序列

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

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

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

2、接口描述

cpp
 ​
class Solution {
public:int sumOfPowers(vector<int>& nums, int k) {}
};
 ​

3、原题链接

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


二、解题报告

1、思路分析

py无脑@cache O(N^5)记忆化搜索 和 本方法跑的差不多就离谱……

我们考虑差值最多有 (n - 1) * n / 2种

定义状态 f(d, i, j) 前 i 个数,拿了 j 个数 , 最小差值 >= d的能量和

第一维直接滚动数组优化掉,然后对nums预排序

那么我们从小到大枚举d,每次做dp都相当于01背包,即每个数选或不选

不选:f(i, j) = f(i - 1, j)

选:f(i, j) += f(last[i], j - 1),last[i] 为 nums[i] - nums[k]  >= d中最靠右的k,这个可以O(NlogN)预处理

然后由于我们定义状态是 >= d的能量和,我们不知道其中有多少=d的

事实上我们这样计算即可:res += (d - prev) * f[n][k],prev为上一个枚举的差值

由于我们是从小到大枚举d的,所以我们每次少算的差值都可以在下一次算上

2、复杂度

时间复杂度: O(N^4)空间复杂度:O(N^2)

3、代码详解 ​

cpp
 ​
using i64 = long long;
constexpr int P = 1'000'000'007;
void add(int& x, i64 y) {x = (x + y) % P;
}
class Solution {
public:int sumOfPowers(vector<int>& nums, int k) {int n = nums.size();vector<int> dif; std::ranges::sort(nums);for(int i = 0; i < n; ++ i) for(int j = 0; j < i; ++ j) dif.push_back(nums[i] - nums[j]);std::ranges::sort(dif);dif.resize(unique(dif.begin(), dif.end()) - dif.begin());int ans = 0, prev = 0;for(int d : dif) {std::vector<int> last(n + 1);for(int i = 1; i <= n; ++ i) last[i] = std::upper_bound(nums.begin(), nums.end(), nums[i - 1] - d) - nums.begin();std::vector<std::vector<int>> f(n + 1, std::vector<int>(k + 1));f[0][0] = 1;for(int i = 1; i <= n; ++ i) {for(int j = 0; j <= k; ++ j) {f[i][j] = f[i - 1][j];if(j > 0 && last[i] < i) {add(f[i][j], f[last[i]][j - 1]);}}}add(ans, 1LL*(d - prev) * f[n][k] % P);prev = d;}return ans;}};
关键字:01背包+枚举,

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: