T1狩影·进击

容易证明,Kendieer 的最佳决策是每过x秒吃掉一个a值最大的企鹅士兵。

问题的核心在于如何计算企鹅大军的总伤害。考虑将每个连续的 秒合并计算(因为在这段时间内,企鹅大军造成的每秒伤害不变): 秒的总伤害 =

因此,将企鹅大军按照a值从小到大排序后,重复执行以下过程:计算每x秒的企鹅伤害,删去末尾的企鹅。时刻判断总伤害是否大于初始血量即可。

T2雪遁·逃生

题意:把字符串 划分成若干连续子串,子串序列字典序不下降,求最多段数。

预处理任意后缀对的最长公共前缀 ,使任意两段比较 在常数时间内可判定谁更大。设 长度, 。若 则任意长度 都满足 ;否则通过比较 得出结论。

考虑动态规划,设状态 表示将前缀 划分且最后一段为 时的最大段数。初始化 (把前缀当一段)。

状态转移过程为:若上一段为 ,下一段为 ,当且仅当 时可转移:

对于固定 ,满足 是从某个最小 开始到 的连续区间,因此只需算出 (用 常数时间得到)。

对区间更新进行优化,对每个 记录各 对应的最小起始位置 的候选值,然后做一次前缀最大化把 批量写回 。这样把枚举三重循环的第三层合并,整体变为

答案为

时间复杂度:预处理 ,动态规划

T3神木·溯源

考虑树形 。需要维护的信息如下:

表示仅考虑以 为根的子树中,强制选取 时的最大答案;

表示考虑整棵树中,强制选取 时的最大答案;

表示仅考虑以 为根的子树中的最大答案;

表示考虑整棵树中,强制选取 时的最大答案。

计算上述四个函数:

  • ,其中 表示 上方能与 相连的最大答案。可结合祖先的 函数在 过程中顺带计算得出 (细节见标程);
  • ,其中 表示 上方的最大答案。

可结合祖先的 三个函数在 过程中顺带计算得出 (细节见标程)。

在上述四个函数的基础上计算答案:

不为 ,则答案即为上述表达式(选取 和不选取 的两种情况取较大值);

,则答案为整棵树中最大的一个点权(因为不能选取空集)。

T4试炼·终境

先将问题转化为“对于每个 ,都寻找一个数与 配对”。观察发现,想要不“浪费”任何一个二进制位,就要尽可能地让所有二进制位互补。例如: 配对, 配对。

可以先尝试计算一下 可能的上界。对于每一个二进制位,若 中的所有数字在该位上 “” 的个数之和大于 “” 的个数之和,则显然无法通过配对使所有的 “” 都被利用上(也就是说,肯定要“浪费”至少一个 ),例如有三个数 ,那么在二进制的第 位上有 个 “” , 个 “” 。又由于所有数字是 的排列,故该位上 “” 的个数之和至多比 “” 的个数之和大 。综上, 的一个上界为 减去所有满足条件( “” 的个数之和大于 “” 的个数之和)的二进制位的值。

存在多种能达到这种答案上界的构造方法,以下介绍其中相对简单的一种。

表示当前需要考虑 中各个数字对应的 值,令 (以 的最高位)取反后的值:

  • 不为 ,则对于 范围内的每一个数 ,令 。而后,令

  • ,则 。而后,令

反复执行以上过程直到 即可。

T5时锁·封印

在本篇题解中作以下约定:最终答案指要求输出的答案,选取子串指最终答案在进行循环排列之前的结果,最大字符指输入的字符串中字典序最大的字符,连续段指由若干最大字符组成的子串。

根据本题的要求,想要找到字典序最大的答案,需要优先考虑最大字符。不难理解,最终答案的开头一定是最大字符。

先进行一个分类讨论:

假设存在若干由最大字符组成的连续段(比如样例中的 就存在 两个连续段)。由于可以进行循环排列,故选取子串的首尾一定是恰好两个连续段。因为这样可以使最终答案的开头由更多的最大字符构成。

假设仅存在一个由最大字符组成的连续段,那么它一定在选取子串中。

关键观察:最长的(如果存在同样长的则取最靠后的)连续段,一定会出现在最终答案中。

证明:如果不存在同样长度的连续段,则结论显然成立;如果存在同样长度的连续段,采用反证法,若选取子串不包含最长且最靠后的连续段,那么选取子串的首尾一定都是同样长度的连续段,此时若将尾部延伸至最靠后的连续段,等价于在最终答案之后添加了一段字符,根据字典序的定义,不如选取最靠后的连续段更优。

于是,我们可以根据上述分类讨论进一步研究实现方法:

如果存在若干由最大字符组成的连续段,那么最靠后的最长连续段一定是选取子串的开头或结尾。若在开头,则将该连续段之后的整个子串截取出来,再寻找一次最靠后的最长连续段作为选取子串的结尾即可。若在结尾,则将该连续段之前的子串截取出来,则问题等价于选取一个最大的后缀。可以在 复杂度完成或使用后缀数组在 的复杂度内完成。两种情况取字典序最大值即可。

如果仅存在一个由最大字符组成的连续段,则先将该连续段之前的子串截取出来,仍然选取一个最大的后缀。而后,再将该连续段之后的子串截取出来,逐个枚举并添加前缀字符,直到该字符小于前述后缀的开头字符即可。需要留意边界情况。

总时间复杂度和空间复杂度均为

T6时殒·残篇

将内层的两个求和看作一个整体,即先计算 。不难发现,对于每个 ,存在唯一的 使得 。其实际意义是将集合 划分为若干个互不相交的子集 ,由于 的唯一性,所有 的并集即为 ,做到了遍历所有的 。因此, ,原式化为

,原式变为 。把 ,并令 (易知若 则答案为 ),条件 等价于 。于是问题变为

的不同质因子列出来(设其数量为 )。利用容斥原理,把 的求和转换为对质因子子集的枚举:

对任意由质因子子集对应的乘积 ,令符号为 ,则

,得到我们需要计算的核心子问题:对某个 和上界 (这里 ),求

因此总体算法流程是枚举所有子集(最多 ,对于 ),对每个子集计算一次 并按符号累加。

对固定的 ,函数 是关于 的一个多项式,次数为 。有 公式:

其中系数 可通过伯努利数 来写成显式形式。常用形式为

因此若已知系数 ,对某个

把它代入

于是问题变为:对于每个 计算

直接用上面的 公式计算 (用伯努利数)对单个 的,若对所有 都做则是 每个 。我们需要把对每个 的计算批量化并尽可能加速。

利用伯努利数可得:

把此式按 取所有 ,我们可把“对所有 的运算”组织成一个卷积问题,从而用 (模 的原根适合 )把复杂度降到

首先需要预先计算伯努利数序列 ,采用 递推或 生成函数的方法均可。

令序列

则卷积 在下标 上等于

,得到

于是

所以只要做一次长度约 的卷积()就能同时得到所有 )。

因为对于不同的子集我们会遇到不同的 (但数量 上界为子集数 ),我们对每个不同 做一次上述 并缓存结果,避免重复计算。

总体时间复杂度: