看到要求“字典序最小”的方案,一个很直观的想法是按位贪心,那么我们需要check的就是当某一个数放在了第一个序列之后是否还存在方案。
假设当前两个序列的最大值和前缀最值数量分别为(Mx_1 , Mx_2 , cnt_1 , cnt_2),那么我们要求在剩下的数列中选出两个序列({a},{b})满足
(Mx_1 < a_1 < a_2 < ... < a_{k_1}) , (Mx_2 < b_1 < b_2 < ... < b_{k_2}) , (cnt_1 + k_1 = cnt_2 + k_2) , 且原序列的还没有放进去的前缀最大值必须要在(a)或者(b)中出现。
对于没有出现在(a)或者(b)中的元素,我们可以直接把它们安排在它们的前缀最大值之后,就可以避免产生贡献。
注意到一件事情:如果(a)和(b)中同时存在不是前缀最大值的元素,那么我们可以在这两个序列中同时删掉一个这样的元素,原序列仍然是合法的。所以一定存在一种方案,至少一个序列中全部都是前缀最大值。不妨设序列({a})中不存在非前缀最大值。
不妨设剩余元素中前缀最大值个数为(q),在({b})序列中存在(k)个原序列的前缀最大值,存在(m)个非前缀最大值,那么有(cnt_0 + q - k = cnt_1 + k + m),即(2k + m = cnt_0 + q - cnt1)。右边是一个定值,那么我们相当于需要求出一个上升子序列,使得当原序列前缀最大值权值为(2)、非前缀最大值权值为(1)时的权值和等于某个值。
注意到如果某个上升子序列权值为(k),那么一定存在权值为(k-2)的上升子序列,所以我们只要求出权值为奇数/偶数的所有上升子序列的最大权值。那么我们可以使用线段树做一个DP:设(f_{0/1,i})表示以(i)开头的所有权值为奇数/偶数的上升子序列中的最大权值,转移是线段树上的区间查询和单点修改。
那么我们的查询就可以变为在线段树上查询:以位置在当前判断的位置之后、数值大于某个值的所有位置为开头的上升子序列的最大奇数/偶数权值。因为每一次判断的位置是单调递增的,所以也可以通过线段树进行查询。