1 条题解

  • 0
    @ 2025-10-30 11:22:34

    问题理解

    我们有一个排列 ( p[0], p[1], \dots, p[n-1] ),它是 ( 0 ) 到 ( n-1 ) 的一个排列。
    我们只能选择一些行星来加速,并且选择的行星对应的轨道速度必须严格递增。
    也就是说,选择的索引集合 ( i_1 < i_2 < \dots < i_m ) 必须满足 ( p[i_1] < p[i_2] < \dots < p[i_m] )。
    这就是排列的递增子序列(不要求连续)。

    题目要求:
    给定 ( k ),构造一个长度 ( n ) 尽量小的排列,使得它的递增子序列个数恰好等于 ( k )。


    关键思路

    1. 空子序列

    递增子序列包括空序列,所以如果排列的递增子序列总数为 ( k ),那么非空子序列数是 ( k-1 )。
    但题目中给的 ( k ) 是包含空序列的(从样例可以看出:( k=3 ) 时,子序列有 [], [0], [1] 共 3 个)。


    2. 已知结论

    一个常见的构造方法是利用二进制分解斐波那契分解来构造排列,使得递增子序列数恰好为 ( k )。

    一种简单的方法:

    • 考虑在排列末尾添加一个比之前所有数都大的数,那么递增子序列数会翻倍(因为所有原来的子序列都可以加上这个新数,形成新的递增子序列)。
    • 考虑在排列末尾添加一个比之前所有数都小的数(比如 0),那么递增子序列数会加 1(因为只有这个新数单独作为一个子序列,以及空序列加上它)。

    3. 构造方法(二进制法)

    假设 ( k ) 的二进制表示是 ( 1b_{m-1}b_{m-2}\dots b_1 )(最高位是 1)。
    我们从空排列开始,递增子序列数初始为 1(空序列)。

    从左到右处理二进制位(从最高位之后的位开始):

    • 如果当前位是 1:先执行“翻倍”操作(加一个最大数),再执行“加 1”操作(加一个最小数)。
    • 如果当前位是 0:只执行“翻倍”操作。

    这样,每个 1 对应“×2+1”,每个 0 对应“×2”。


    例子
    ( k = 6 )(二进制 110

    • 初始:[],子序列数 = 1(空序列)
    • 二进制 110,从第二位开始:
      • 第二位 1:翻倍(加最大数 0) → [0],子序列数=2;再加 1(加最小数 1 到前面) → [1,0],子序列数=3。
      • 第三位 0:翻倍(加最大数 2) → [1,0,2],子序列数=6。

    检查 [1,0,2] 的递增子序列:

    • []
    • [1]
    • [0]
    • [2]
    • [0,2]
    • [1,2] 共 6 个,正确。

    4. 更优的构造(使用最长递增子序列 LIS 计数技巧)

    实际上,更优的方法是使用一种排列,它的递增子序列数可以表示为 2 的幂次乘积
    例如:

    • 排列 [0]:子序列数 = 2([], [0]
    • 排列 [0,1]:子序列数 = 4([], [0], [1], [0,1]
    • 排列 [1,0]:子序列数 = 3([], [0], [1]

    我们可以把 k 分解成 ( k = 2^{a_1} + 2^{a_2} + \dots ) 的形式,然后构造对应块。


    块构造法

    • 一个长度为 ( m ) 的递增序列(如 0,1,...,m-1)的递增子序列数是 ( 2^m )(每个元素选或不选)。
    • 一个长度为 ( m ) 的递减序列(如 m-1, m-2, ..., 0)的递增子序列数是 ( m+1 )(只能选一个元素或空序列)。
    • 我们可以把 k 写成二进制,每一位对应一个块,块之间用“隔断”方式保证不跨块形成新的递增子序列。

    具体做法:

    • 将 k 写成二进制,设最高位是 ( 2^m )。
    • 构造一个 0,1,...,m-1 作为第一个块(子序列数 ( 2^m ))。
    • 对剩下的位数(从高到低),如果某位为 1,就加一个递减序列块,长度等于该位代表的幂次,并确保这个块的所有数大于之前所有数,这样不会和前面形成跨块递增子序列,但块内部贡献 ( \text{长度}+1 ) 的子序列数。
    • 最后排列的总递增子序列数就是各块贡献的乘积,等于 k。

    5. 长度优化

    这种方法得到的长度大约是 ( O(\log k) ) 级别,通常很短,满足题目要求。


    总结

    题解的核心是:

    1. 理解排列的递增子序列计数规律。
    2. 利用二进制分解,将 k 拆成若干 2 的幂次组合。
    3. 用递增块(贡献 2 的幂)和递减块(贡献幂次+1)拼接构造。
    4. 确保块之间数字大小关系,避免跨块产生额外递增子序列。

    这样就能在 ( n \le 120 ) 内构造出符合要求的排列,满足题目约束。

    • 1

    信息

    ID
    4281
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    11
    已通过
    1
    上传者