1 条题解
-
0
「OOI 2016 Day 1」缆车 题解
核心思路
1. 问题分析
我们需要处理 个独立查询,每个查询修改一个位置的值后,求新序列的最长严格递增子序列 (LIS) 长度。
直接对每个查询重新计算 LIS 会超时,需要预处理。
2. 关键观察
设原序列为 ,修改位置 的值为 。
新序列的 LIS 可能:
- 不包含修改位置
- 包含修改位置
3. 预处理数组
定义:
- :以位置 结尾的 LIS 长度(正向 DP)
- :以位置 开始的 LIS 长度(反向 DP)
- :原序列的 LIS 长度
4. 分类讨论
对于查询 :
情况 1:不包含位置
此时 LIS 长度 = 原序列去掉位置 后的 LIS 长度
但直接去掉 可能影响 LIS,更精确地:
- 如果位置 是原序列所有 LIS 的必经点,则去掉后长度减 1
- 否则长度不变
实际上,我们可以计算:
情况 2:包含位置
此时 LIS 由三部分组成:
- 左边,结尾值 的最大 值
- 位置 本身(贡献 1)
- 右边,开始值 的最大 值
即:
$$\text{ans}_2 = \max_{i < p, h[i] < v} f[i] + 1 + \max_{j > p, h[j] > v} g[j] $$5. 数据结构优化
为了高效计算 ,需要:
预处理:
- 对每个位置 ,维护左边所有 的信息
- 对每个位置 ,维护右边所有 的信息
查询时:
- 在左边信息中查询 的最大
- 在右边信息中查询 的最大
可以使用:
- Fenwick 树或线段树维护前缀/后缀最大值
- 对高度离散化处理
6. 计算不经过 的 LIS
定义 :有多少个 LIS 经过位置
如果 ,则存在不经过 的 LIS,长度 = 如果 ,则不经过 的 LIS 长度 =
计算 的方法:
- 正向 DP 时记录方案数(取模避免溢出)
- 或者判断: 且该 值唯一
7. 算法流程
-
预处理阶段:
- 计算 :正向 LIS DP
- 计算 :反向 LIS DP
- 计算 :每个位置被多少 LIS 经过
- 构建左边和右边的数据结构
-
查询阶段:
- 对于查询 :
- $\text{ans}_1 = \begin{cases} L & \text{if } cnt[p] > 1 \\ L-1 & \text{otherwise} \end{cases}$
- $\text{ans}_2 = \text{leftMax}(p, v) + 1 + \text{rightMax}(p, v)$
- 输出
- 对于查询 :
算法实现
复杂度分析
- 预处理:
- 每个查询:
- 总复杂度:
关键数据结构
>// 左边:对于每个位置p,维护h[1..p-1]的(h, f)信息 vector<Fenwick> leftTrees; // 右边:对于每个位置p,维护h[p+1..n]的(h, g)信息 vector<Fenwick> rightTrees;
- 1
信息
- ID
- 4721
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者