当前位置: 首页 > news >正文

豆包 LeetCode 3082. 求出所有子序列的能量和 Java实现

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

📌 题意理解

数组的能量= 其内部和等于 k 的子序列的个数

要你求:nums 的所有子序列各自的能量,加起来是多少(mod 1e9+7)。

本质上是「子序列的子序列」计数问题——对每个候选子序列 S(sum(S)=k),它会出现在多少个 nums 的大子序列 T 里?


💡 核心转换(关键洞察)

假设有一个确定的子序列S ⊆ nums,sum(S) = k,|S| = len

nums 中不包含在 S 里的元素n - len个,每个可选可不选地塞进 T 里,所以:

S 对答案的贡献 = 2^(n - |S|)

因此:

\text{ans} = \sum_{\substack{S \subseteq \text{nums} \\ \text{sum}(S) = k}} 2^{\,n - |S|}

提出 2ⁿ,等价于追踪每个和为 k 的子序列的2^(-|S|)权重和。


🔑 DP 设计

dp[j]= 已处理元素中,所有和为 j的子序列对应的2^(-len)的累积和。

  • 初始:dp[0] = 1(空子序列,sum=0,len=0 → 2⁰=1)

  • 处理每个数x时:

    • 不选 x:已有子序列仍可存在,且剩余"自由位"多了一位 → 所有 dp 值×2

    • 选 x:从dp[j-x]转移过来,选了 x 后长度 +1 → 相当于原来的贡献× ½,即加上dp_old[j-x]

inv2表示 2 的模逆(MOD+1)/2 = 500000004

状态转移(一维优化,从后往前)

dp_new[j] = dp_old[j] × 2 ← 不选 x + (j≥x ? dp_old[j-x] : 0) ← 选 x(贡献不变,因为 ×2 和 ×½ 抵消的视角)

实际更干净的形式直接用乘法:

dp[j] = dp[j] \times 2 + (j \ge x ? dp[j-x] : 0)

✅ Java 实现

版本一:一维 DP(推荐,O(n·k) 时间,O(k) 空间)

class Solution { public int sumOfPower(int[] nums, int k) { final int MOD = 1_000_000_007; int n = nums.length; // dp[j] = 所有和为 j 的子序列的累计贡献 // 最终 dp[k] 就是答案 long[] dp = new long[k + 1]; dp[0] = 1; // 空子序列 for (int x : nums) { // 必须从后往前遍历(0-1背包) for (int j = k; j >= 0; j--) { // 不选 x:原有方案依然存在,贡献 ×2(x成了"自由元素") dp[j] = (dp[j] * 2) % MOD; // 选 x:从和为 j-x 的状态扩展过来 if (j >= x) { dp[j] = (dp[j] + dp[j - x]) % MOD; } } } return (int) dp[k]; } }

版本二:二维 DP(更好理解,O(n·k) 空间)

class Solution { public int sumOfPower(int[] nums, int k) { final int MOD = 1_000_000_007; int n = nums.length; // dp[i][j] = 从前 i 个元素中,选出和为 j 的子序列的总贡献 int[][] dp = new int[n + 1][k + 1]; dp[0][0] = 1; // 空子序列 for (int i = 1; i <= n; i++) { int x = nums[i - 1]; for (int j = 0; j <= k; j++) { // 不选 nums[i-1]:之前的贡献还在,且多了一个自由位 → ×2 dp[i][j] = (int)((dp[i - 1][j] * 2L) % MOD); } for (int j = x; j <= k; j++) { // 选 nums[i-1]:锁定在子序列内,不加自由位,直接累加 dp[i][j] = (dp[i][j] + dp[i - 1][j - x]) % MOD; } } return dp[n][k]; } }

🔍 用示例走一遍

nums = [1,2,3], k = 3,答案为6

和为 3 的子序列 SS贡献 = 2^(3-S)
[3]12² = 4
[1,2]22¹ = 2
合计6

⏱️ 复杂度

时间空间
二维O(n·k)O(n·k)
一维优化O(n·k)O(k)

约束n ≤ 100, k ≤ 100,完全轻松跑过 🎯

这道题本质是带贡献系数的 0-1 背包,难点在于想到把"所有子序列的能量和"转换成"每个 sum=k 的子序列被多少个大子序列包含"——一旦转过弯来,就是标准背包模板了。

http://www.zskr.cn/news/1485189.html

相关文章:

  • 第32章:AI辅助去中心化身份(DID)——链上可验证凭证
  • 科研信息流操作系统:arXiv自动化+结构化笔记+知识图谱闭环
  • 手把手教你排查华为桌面云FusionAccess用户登录失败问题(附详细日志分析)
  • 广元母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • Android启动安全实战:手把手教你用avbtool给dtbo.img镜像签名(附完整命令)
  • 2026年众智商学院PMP班期确认加微信怎么问?官网400冯老师考前冲刺咨询 - 众智商学院职业教育
  • 第35章:AI辅助开发者工具——自动生成ABI文档与TypeScript类型
  • 哪家钢格板厂家专业?2026年6月推荐TOP5对比项目防腐蚀评测案例适用场景 - 品牌推荐
  • 深入理解JavaScript执行机制:从执行上下文到调用栈,八个代码示例彻底搞懂变量提升和作用域
  • 阜新母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • 如何快速从科研图表中提取数据:WebPlotDigitizer完整指南
  • 2026年6月厨房用品供应链生产厂家推荐,小家电供应链/小家电尾货/日用百货供应链,厨房用品供应链直销厂家推荐 - 品牌推荐师
  • 从故障录波到数据分析:COMTRADE文件在继电保护调试中的完整工作流
  • 避开这些坑!TMS320F280049 SDFM模块调试常见问题与解决方案汇总
  • 2026 安徽阜阳市彩钢瓦修缮 TOP4 权威推荐 + 避坑指南(全区域服务) - 本地便民网
  • 数据科学落地五大硬核实战洞察:从问题定义到模型可观测性
  • Advanced Matplotlib:数据可视化中的信息架构与认知效率
  • C#反编译工具横评:dotPeek、ILSpy、dnSpy到底怎么选?附.NET 8实战对比
  • 告别乱码!用PCtoLCD+ESP32在OLED上显示自定义汉字(保姆级图文教程)
  • 广汉母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • 鸿蒙Next实战开发(五):编译构建、调试运行与踩坑总结
  • 从AD9361到USRP X410:三大射频发射架构实战选型指南(直接变频/超外差/直接中频)
  • 碧蓝航线终极自动化脚本:7x24小时智能托管解放双手
  • 高邮母婴除甲醛CMA甲醛检测治理公司深度测评:绿呼吸环保稳居榜首 - 一修哥咨询
  • JetBrains dotPeek 2024.2 保姆级安装与反编译实战:从DLL到C#源码的完整还原
  • 3分钟学会:百度网盘直链解析终极教程,告别限速烦恼!
  • MounRiver工程配置避坑指南:从零配置沁恒MCU头文件、库路径与Linker Script
  • 寄件不用跑腿!手机一键下单,大小件全部上门取件 - 时讯资讯
  • Quartus 18.1 + DE10-Lite开发板:保姆级图文教程,带你跑通第一个NIOS II程序
  • OBD诊断协议揭秘:ISO15031 $02服务如何让ECU‘冻结’故障瞬间(附PID速查表)