2025.04.10 CW 模拟赛 D. 绳网委托

D. 绳网委托

原题链接.

题目描述

给定只由 \(0,1\) 组成的序列 \(a\). 你可以进行若干次操作, 每次操作任意选取一个区间 \([l,r]\), 将 \(a_l, a_{l+1}, a_{l+2}, \cdots, a_r\) 翻转为 \(a_r, a_{r-1}, a_{r-2}, \cdots, a_l\), 求操作后序列的最长不降子序列的长度最大为多少.


思路

下文称 LIS 表示最长不降子序列.

可以发现, 当我们操作区间的两端在连续段中间显然不优, 所以每一段可以视作一个整体.

因为原序列中只含 \(0, 1\), 于是最终的 LIS 一定是形如 \(0 \dots 01 \dots 1\) 的.

如果不考虑翻转操作, 我们可以考虑枚举断点 \(x\), 也就是 \(01\) 分界点来计算答案. 假设 \(cnt_{0 / 1}\) 表示整个序列 \(0/1\) 的数量, \(pre, suf\) 分别表示前后缀 \(0 / 1\) 的数量, 那么在 \(x\) 时答案为

\[pre_{x, 0} + suf_{x + 1, 1} \]

这个式子有两个变量, 不好操作, 考虑换一种表达方式. 观察到 \(suf_{x + 1, 1} = cnt_1 - pre_{x, 1}\), 所以原式还可以写成

\[cnt_1 - pre_{x, 1} + pre_{x, 0} \]

倘若我们将原序列中的 \(0\) 权值设为 \(1\), \(1\) 的权值设为 \(-1\), 那么 \(pre_{x, 0} - pre_{x, 1}\) 就是相当于一段前缀. 所以我们的问题就转化为了找出最大的前缀.

回归到原问题, 要求我们求出进行至多 \(k\) 次翻转之后的最大前缀. 不难发现操作 \(k\) 次后的前缀, 相当于在原串中选出互不相交的一个前缀\(k\) 段区间. 现在原问题就转化为了求出权值和最大的 \(k + 1\) 段区间, 其中一段为前缀.

考虑使用反悔贪心 \((\)模拟费用流\()\) 进行维护. 对于这道题, 具体来说, 我们首先选取一个权值和最大的前缀, 并将前缀中的所有权值取反, 然后每次选取一个权值和最大的子区间, 同样也将权值取反.

这是一个经典模型. 反悔贪心的操作主要体现在取反上, 如果我们后续取到了取反了的区间, 说明我们「反悔」了.

代码P6821 [PA 2012] Tanie linie的. 转化过后属于同一道题, 只是这道题钦定必须取一段前缀.

posted @ 2025-04-10 20:41  Steven1013  阅读(38)  评论(0)    收藏  举报