zoukankan      html  css  js  c++  java
  • 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)开头的所有权值为奇数/偶数的上升子序列中的最大权值,转移是线段树上的区间查询和单点修改。

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

    代码

  • 相关阅读:
    论文(卷积数据流)-Communication Lower Bound in Convolution Accelerators
    CPU架构相关
    Verilog-数据包检测器
    多比特乘法器的分解
    Verilog-数字时钟无毛刺切换
    Booth乘法器
    C++:地平线2019相关题
    C++:char数组和string类
    C++:strcpy函数
    半导体 semiconductor 相关知识
  • 原文地址:https://www.cnblogs.com/Itst/p/11145792.html
Copyright © 2011-2022 走看看