1 条题解

  • 0
    @ 2026-9-3 10:36:56

    Sum 题解

    思路

    令 Pi(x)P_i(x) 表示从第 ii 个序列取前 xx 个数的和。由于原序列不降,PiP_i 的相邻差分不降,所以它是离散凸函数。

    固定总选取数为 kk。若某个方案中有两个序列都只取了非空且非完整的前缀,那么可以在这两个序列之间不断转移一个选取名额。两个序列的总收益关于转移量仍然是凸函数,区间最大值一定在端点取得。因而总能把其中一个序列变成空序列或完整序列而不降低答案。重复此过程可知:存在最优方案,其中至多一个序列只取部分前缀,其余序列要么不取,要么整段取完。

    这给出三层算法。

    1. 小规模直接做分组背包。依次处理每个序列,枚举从该序列取多少个前缀元素,复杂度与所有可选前缀数成正比。
    2. 中等规模枚举唯一可能的部分序列。对其余序列只保留“不取”和“整段取完”两个选择,做一次 0/1 背包后枚举该特殊序列的前缀长度。
    3. 满分算法用分治消除重复背包。递归处理区间 [l,r][l,r] 时,维护区间外所有序列作为完整物品的背包。进入左儿子前,把右半区所有完整物品加入背包;进入右儿子时反之。到达叶子 ii 后,背包恰好包含除 ii 外所有序列的完整选择,再枚举 ii 的前缀长度即可。

    做法

    背包数组 dp[j]dp[j] 表示从当前允许整取的序列中恰好选择 jj 个数所能得到的最大和,不可达状态为负无穷。加入一个长度为 tit_i、价值为 Pi(ti)P_i(t_i) 的完整序列时,从大到小更新:

    dp[j]←max⁡(dp[j],dp[j−ti]+Pi(ti)).dp[j]\gets\max(dp[j],dp[j-t_i]+P_i(t_i)).

    分治函数接收区间及区间外背包。若当前是叶子 ii,枚举 0≤x≤min⁡(ti,k)0\le x\le\min(t_i,k),用

    dp[k−x]+Pi(x)dp[k-x]+P_i(x)

    更新答案。否则分别把另一半的完整序列加入背包副本后递归。每一层每个序列至多作为完整物品加入一次,分治共 O(log⁡n)O(\log n) 层。

    使用 64 位整数保存答案,因为最大和可达 3×10113\times10^{11}。

    复杂度

    小规模分组背包的时间复杂度为 O(k∑imin⁡(ti,k))O(k\sum_i\min(t_i,k)),空间复杂度为 O(k)O(k)。

    枚举部分序列算法的时间复杂度为 O(n2k+nk)O(n^2k+nk),空间复杂度为 O(k)O(k)。

    分治满分算法的时间复杂度为 O(nklog⁡n+nk)O(nk\log n+nk),空间复杂度为 O(klog⁡n+∑imin⁡(ti,k))O(k\log n+\sum_i\min(t_i,k))。

    • 1

    信息

    ID
    1255
    时间
    1500ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    0
    上传者