AGC028E High Elements 贪心、DP、线段树

传送门


看到要求“字典序最小”的方案,一个很直观的想法是按位贪心,那么我们需要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\)开头的所有权值为奇数/偶数的上升子序列中的最大权值,转移是线段树上的区间查询和单点修改。

那么我们的查询就可以变为在线段树上查询:以位置在当前判断的位置之后、数值大于某个值的所有位置为开头的上升子序列的最大奇数/偶数权值。因为每一次判断的位置是单调递增的,所以也可以通过线段树进行查询。

代码

posted @ 2019-07-07 11:30  cjoier_Itst  阅读(375)  评论(2编辑  收藏  举报