CF1685E The Ultimate LIS Problem 题解
Link
CF1685E The Ultimate LIS Problem
题意概述
给定长为 的排列,对于 次交换操作,求出每次操作后一个能使排列 的循环移位 ,或报告无解。
Step 1
先不考虑操作,对一个排列考虑问题。
数据范围显然不支持我们 , 的限制看得我们一头雾水,索性 一下。
根据 定理,若 ,则覆盖原序列需要至少 个下降序列。
所以 等价于:原序列可以被 个以内的下降序列覆盖。
我们不需要最小化 ,所以构造一个 个下降序列的划分方式就足够了。
Step 2
因为排列长为 ,考虑掏出一个数,剩下的两两配对完再把它插回去。
一定存在让这剩下 个数能够两两配对成下降序列的循环移位。
更准确的说,一定存在让剩下 个数中较大的 个与较小的 个两两配对的循环移位。
为什么呢?
不妨把较大的数看作左括号,较小的数看做右括号,问题转成求一个循环移位使其构成合法括号序列。
规定左括号权值为 ,右括号权值为 ,考虑该权值的前缀和。
当该权值在每个位置的前缀和均 时,该序列较大的 个数恰好能与该序列较小的 个数两两配对。
对于任意一个前缀和最小的位置 ,把 移位到末尾,得到的新序列都满足上面的约束。(不理解可以画折线图辅助理解)
如果觉得不够自然,可以先看看同场比赛的 C 题,思考方式有相似之处。
Step 3
现在考虑怎么把掏出来的数合法地插回去。
首先,刚才的移位对我们掏出来的数还是有影响的,我们大可不必真的把它掏出来,在计算括号权值的时候把它当成 就够了。
假如我们掏出来的数是 ,只要在括号序列中被括进了一对括号里,它就可以插进那对括号对应的下降序列中,答案 就是刚才移位的 。
这并没有考虑完所有的有解情况,但性质足够优秀,不妨就钦定我们掏出来的数是 。
对于剩下的情况, 刚好不被任何一对括号括起来,意味着 不可能在下降序列的中间了,所以考虑 在两头的情况。
在刚才的移位后 可能还在序列的中间,看看能不能把它挪到两头来。
发现 两侧一定都是合法括号序列,直接挪到一起, 就到了两头,正合我意。
当 在最右边时,如果序列中的 不是单调上升的,即对于靠左的数 ,靠右的数 ,存在 ,我们可以把 接到 那个下降序列的后面,这样原来和 匹配的大于 的数就空了出来。
那我们就可以把 接上去啦。
相应的,当 在最左边时,如果序列中的 不是单调上升的,我们也可以空出一个小于 的数,来和 接到一起。
在最左边的答案就是 加上左边挪动的那段合法括号序列长度,
在最右边就再加上 。
如果两种接法都不可行,意味着至少有 个下降序列才能覆盖原序列的某个循环移位,报告无解。
Step 4
对于单个排列,我们已经能够在 的时间复杂度内应答,再考虑交换操作。
刚才的问题中,我们需要解决的子问题有: 序列前缀和的 ,区间中 , 的数的单调性,均可用线段树维护带修答案。
总时间复杂度为 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?