B. 美食节
思路
令 \(f_{i, j}\) 表示第 \(i\) 个活动后在 \(j\) 的最小疲劳值.
对于每一个 \(f_{i, j}\), 先从 \(f_{i - 1, j}\) 赋值过来, 接下来由两部分贡献.
第一部分:
\[f_{i, j} = f_{i - 1, j} +
\begin{cases}
l_i - j & j < l_i \\
j - r_i & j > r_i
\end{cases}
\]
第二部分对于移动的贡献, 我们使用 \(f_{i, j} + 1\) 更新 \(f_{i, j \pm 1}\).
事实上, 如果我们对于 \(f_{i, j}\) 进行差分, 那么只会有 -1, 0, 1 这三段.
归纳证明一下. \(i = 0, f_{i, j} = |j - x|\), 显然成立. 当 \(i\) 增大时, 第一部分计算会让函数再加上一个差分为 -1, 0, 1 的函数, 也就是 \(f_{i, j}\) 差分会变成 -2, -1, 0, 1, 2; 但是第二部分的贡献又会使函数的差分绝对值不超过 1, 又变回 -1, 0, 1.
这样, 差分值为 0 的段便为最小答案, 用两个变量维护即可. 时间复杂度 \(\mathcal{O}(n)\).
read(n, l), r = l;
for (int i = 1, x, y; i <= n; ++i) {read(x, y);if (r < x) ans += x - r, l = r, r = x;else if (l > y) ans += l - y, r = l, l = y;else l = max(l, x), r = min(r, y);
}