2786. 访问数组中的位置使分数最大
考点
- 状态机DP
- 初始值设置
- 状态设计
一、题目核心规则抽象
给定数组 nums,从 下标 0
必须开始访问,每次可以跳到任意更大的下标:
- 如果 相邻两次访问的数字奇偶相同:✅ 不扣分
- 如果 奇偶不同:❌ 扣
x - 每访问一个位置,都会获得
nums[i]分数
目标: \[ \text{最大化总得分} \]
二、奇偶区间(Parity Segment)建模思想
由于:
nums[i] > 0- 同奇偶不扣分
所以得到一个非常重要的结构性质:
✅ 在一段连续“同奇偶区间”里,一旦进入,就一定全部取完。
因此整个路径的真正“决策点”,只发生在:
🔥 奇偶发生切换的分界点
示例:奇偶区间拆分示意图
1 | nums = [ 2, 4, 6 | 3, 9, 1 | 8, 10 ] |
在每个“段内”:
- 一定是:
\[ \text{当前奇偶和} += nums[i] \]
只有在 段与段之间,才需要在: \[ \text{是否支付 } x \text{ 扣分} \;\; vs \;\; \text{是否切换奇偶} \] 做博弈选择。
三、 DP 状态定义
设: \[ \begin{aligned} even &= \text{当前处理到 i 为止,\textbf{最后一个访问的是偶数}的最大得分} \\ odd &= \text{当前处理到 i 为止,\textbf{最后一个访问的是奇数}的最大得分} \end{aligned} \] ⚠️ 特别注意:
even和odd不是当前“区间和”- 而是:全前缀最优路径的结束状态
四、最关键的错误:初始化 = 0 是“伪路径”
一开始的错误初始化是:
1 | if (nums[0] & 1) |
这在数学上等价于:
❌ “存在一条合法路径: 没有经过 0,却已经以奇/偶结尾,得分为 0”
但题目规定:
✅ 必须从下标 0 开始访问
因此:
如果
nums[0]是偶数: \[ odd = -\infty \]如果
nums[0]是奇数: \[ even = -\infty \]
这正是最终 AC 的修复:
1 | if (nums[0] & 1) |
❗ 错误初始化会导致什么后果?
会引入一条“从中间元素单独起跳”的非法路径:
例如:
1 | even = 58 |
当遇到一个奇数 65 时: \[
odd = \max(\underbrace{0 + 65}_{非法路径},\; 58 + 65 - 74)
\] 结果错误选择了 65,而正确值应该是 49。 这正是 输出 486
而不是 470 的根本原因。
五、DP转移
现在 AC 的转移策略是:
① 非分界点(同奇偶)
1 | if (nums[i] & 1) |
等价于数学式: \[ \text{段内累加}:\quad dp += nums[i] \] ✅ 因为同奇偶不扣分,且所有数为正,必取
② 分界点(奇偶切换)
最终 AC 的关键转移是:
1 | if (nums[i] & 1) |
对应数学表达为:
当前是奇数:
\[ odd_i = \max \begin{cases} odd_{i-1} + nums[i] & \text{原本就在奇数段} \\ even_{i-1} + nums[i] - x & \text{刚从偶数段切换} \end{cases} \]
当前是偶数:
\[ even_i = \max \begin{cases} even_{i-1} + nums[i] & \text{原本就在偶数段} \\ odd_{i-1} + nums[i] - x & \text{刚从奇数段切换} \end{cases} \]
✅ 这一层的本质含义:
在“奇偶分界点”,做的是:
- 继续原奇偶 → 不扣
x- 切换奇偶 → 扣一次
x
六、代码结构
1 | 初始化: |
七、AC代码
1 | class Solution { |