3351. 好子序列的元素之和
考点
- 线性DP
思路
一、问题描述
给定一个整数数组
nums,定义一个好子序列为满足以下条件的子序列:
- 子序列中任意相邻两个元素的绝对差值为 1。
要求计算 所有好子序列的元素和之和,结果对 \[ \text{MOD} = 10^9 + 7 \] 取模。
二、问题建模思路
1. 按“结尾值”建模而非按位置
注意到题目对顺序敏感,但合法性仅与相邻元素的值有关。 因此可以不关心子序列的具体位置结构,而是按“子序列最后一个元素的值”进行分类统计。
2. 核心观察
若一个好子序列以值 \(v\) 结尾,那么在其末尾追加一个新元素 \(x\) 后仍为好子序列,当且仅当: \[ |x - v| = 1 \quad \Longleftrightarrow \quad v \in \{x-1, x+1\} \] 此外,单个元素 \([x]\) 本身也是一个好子序列。
三、状态定义
设当前已经扫描到数组前缀,定义以下两个状态数组:
- \(\text{cnt}[v]\):以值 \(v\) 结尾的好子序列个数
- \(\text{sum}[v]\):以值 \(v\) 结尾的好子序列中,所有序列的元素和之和
最终答案为所有新生成好子序列的贡献之和。
四、状态转移推导
1. 新元素 \(x\) 带来的新子序列来源
当处理到一个新元素 \(x\) 时,新生成的、以 \(x\) 结尾的好子序列来自三部分:
新建单元素子序列 \[ [x] \]
从所有以 \(x-1\) 结尾的好子序列扩展
从所有以 \(x+1\) 结尾的好子序列扩展
2. 新增子序列数量
设: \[ \begin{aligned} c_{x-1} &= \text{cnt}[x-1] \\ c_{x+1} &= \text{cnt}[x+1] \end{aligned} \] 则本轮新增的好子序列个数为: \[ \Delta \text{cnt} = 1 + c_{x-1} + c_{x+1} \]
3. 新增子序列的元素和贡献
设: \[ \begin{aligned} s_{x-1} &= \text{sum}[x-1] \\ s_{x+1} &= \text{sum}[x+1] \end{aligned} \]
原有子序列的和整体继承: \[ s_{x-1} + s_{x+1} \]
每个新子序列末尾新增一个 \(x\),贡献: \[ x \times \Delta \text{cnt} \]
因此新增的元素和为: \[ \Delta \text{sum} = s_{x-1} + s_{x+1} + x \cdot (1 + c_{x-1} + c_{x+1}) \]
4. 状态更新方程
\[ \begin{aligned} \text{cnt}[x] &\leftarrow \text{cnt}[x] + \Delta \text{cnt} \\ \text{sum}[x] &\leftarrow \text{sum}[x] + \Delta \text{sum} \end{aligned} \]
同时,将本轮新增贡献累加到全局答案中: \[ \text{ans} \leftarrow \text{ans} + \Delta \text{sum} \] 所有运算均对 \(\text{MOD}\) 取模。
五、算法流程
- 初始化数组
cnt[]、sum[]为 0 - 从左到右扫描
nums - 对当前元素 \(x\),读取
x-1、x+1的状态 - 按转移方程计算新增贡献
- 更新状态并累加答案
- 返回最终答案
六、复杂度分析
时间复杂度: \[ O(n) \] 每个元素仅进行常数次状态转移
空间复杂度: \[ O(V) \] 其中 \(V\) 为值域上界(本题中 \(\le 10^5\))
七、AC代码
1 | class Solution { |