专栏文章

题解:CF2124I Lexicographic Partition

CF2124I题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minza6ki
此快照首次捕获于
2025/12/02 10:47
3 个月前
此快照最后确认于
2025/12/02 10:47
3 个月前
查看原文
这个题太厉害了!
首先第一步你要观察,如何写 spj,也就是根据已知排列求每个前缀的答案。先考虑整个排列 p1,p2,,pnp_1,p_2,\dots,p_n 的答案。
对于字典序最优这种问题,别无它法,必然是贪心。第一个数肯定是 p1p_1,下面想第二个。设最靠前的 <p1<p_1 的位置为 pap_a,则如果 a=2a=2,直接归约到 [2,n][2,n] 的答案;否则考虑 p1ap_{1\sim a} 最大的为 pbp_b,将会归约到 [b,n][b,n] 的答案。
这样就可以 O(n2)O(n^2) 的算整个排列的答案了。但这还远远不够,想要优化,我们必须要换一种思路,从每次往后加一个数的角度入手。
这里我们不加证明的给出(其实直接理解即可),我们可以直接维护一个栈,表示目前的答案。每次加一个数时,就会弹一个后缀,把“在它之前第一个比它大的数到它的区间最小值之后的数”删掉。这样我们就可以很轻松的维护数据结构做到 O(nlogn)O(n\log n) check 了。
回到正向构造部分。
注意到栈的结构十分特殊,因为每个时刻栈的大小都确定了,就为 xix_i,因此弹出多少个元素也是固定的。这就说明,栈里面的所有元素的坐标都是已知的(换句话说,我们知道任意时刻栈都由 pz1,pz2,,pzxip_{z_1},p_{z_2},\dots,p_{z_{x_i}} 构成,zjz_j 是确定的)。
根据这个结构,考虑加完 pip_i 后得到的栈 SiS_i,设倒数第二个元素为 pjp_j(一定存在,因为 p1p_1 永远在栈中)。则 SiS_i 就是 SjS_j 填加 pip_i 的结果。
这启发我们,将 jjii 连一条边,形成一棵树,SiS_i 就是根结点 11ii 的路径顺次排列的结果。
因为一个 pip_i 出现的时间是连续的(被删之后就再也不会复活了),因此它的子树对应的位置也是连续区间,也等价于这棵树的 dfn 序就是 1n1\sim n。因此 ii 如果不是叶节点,则 i+1i+1 一定是 ii 最靠左的儿子。
考虑按一种方式来确定答案。因为点之间的顺序很明确,所以直接 dfs 确定。
可以定义 solve(x,l,r) 表示将确定 xx 的子树,填数范围在 [l,r][l,r] 中。根据直觉,我们要么填最小的数 ll,要么填最大的数 rr。分别考虑对应的情况:
  • 填最小的:儿子之间肯定是从左往右地递增去填(否则到第二个儿子的时候前面删不掉),因此划分区间的方案是固定的。只要前面 <x<x 的部分不捣乱即可。
  • 填最大的:为了防止前面捣乱,相当于加了一个隔离挡板,后面的人删不到前面去,但是如果有多个儿子,就会出现删不掉的点,所以此时 xx 只能有一个儿子。
什么时候会出事?连续两次都只能填最小的,也就是有一对父子同时有 2\geq 2 个儿子。这里给一个充要的证明:
引理:xx 如果有不少于两个儿子,则对于其任意两个儿子,设左边的为 yy,右边的为 zz,则 px<py<pzp_x<p_y<p_z
证明是容易的,就根据我们之前那个模拟栈的思路,到 zz 的时候 pxp_x 会作为最小值把后面的弹掉,而这些数都不能超过 pzp_z,于是就对了。
而如果存在 yyxx 的儿子,zzyy 的儿子,且有 px<py<pzp_x<p_y<p_z,那从优化的角度上,没道理不删 pyp_y,所以就矛盾了。
此时把这种情况排掉之后,就可以直接递归下去构造了,时间复杂度线性。
代码稍微有点写丑了,当时理解还不够深刻。大概思路和本文是相符的,凑合看看吧。

评论

0 条评论,欢迎与作者交流。

正在加载评论...