T1狩影·进击
容易证明,Kendieer 的最佳决策是每过x秒吃掉一个a值最大的企鹅士兵。
问题的核心在于如何计算企鹅大军的总伤害。考虑将每个连续的 秒合并计算(因为在这段时间内,企鹅大军造成的每秒伤害不变):
秒的总伤害 =
。
因此,将企鹅大军按照a值从小到大排序后,重复执行以下过程:计算每x秒的企鹅伤害,删去末尾的企鹅。时刻判断总伤害是否大于初始血量即可。
T2雪遁·逃生
题意:把字符串 划分成若干连续子串,子串序列字典序不下降,求最多段数。
预处理任意后缀对的最长公共前缀 ,使任意两段比较
和
在常数时间内可判定谁更大。设
为
长度,
。若
则任意长度
的
都满足
;否则通过比较
与
得出结论。
考虑动态规划,设状态 表示将前缀
划分且最后一段为
时的最大段数。初始化
(把前缀当一段)。
状态转移过程为:若上一段为 ,下一段为
,当且仅当
时可转移:
对于固定 ,满足
的
是从某个最小
开始到
的连续区间,因此只需算出
(用
常数时间得到)。
对区间更新进行优化,对每个 用
记录各
对应的最小起始位置
的候选值,然后做一次前缀最大化把
批量写回
。这样把枚举三重循环的第三层合并,整体变为
。
答案为 。
时间复杂度:预处理
,动态规划
。
T3神木·溯源
考虑树形 。需要维护的信息如下:
表示仅考虑以
为根的子树中,强制选取
时的最大答案;
表示考虑整棵树中,强制选取
时的最大答案;
表示仅考虑以
为根的子树中的最大答案;
表示考虑整棵树中,强制不选取
时的最大答案。
计算上述四个函数:
,其中
表示
上方能与
相连的最大答案。可结合祖先的
函数在
过程中顺带计算得出
(细节见标程);
,其中
表示
上方的最大答案。
可结合祖先的 三个函数在
过程中顺带计算得出
(细节见标程)。
在上述四个函数的基础上计算答案:
若 不为
,则答案即为上述表达式(选取
和不选取
的两种情况取较大值);
若 为
,则答案为整棵树中最大的一个点权(因为不能选取空集)。
T4试炼·终境
先将问题转化为“对于每个 ,都寻找一个数与
配对”。观察发现,想要不“浪费”任何一个二进制位,就要尽可能地让所有二进制位互补。例如:
与
配对,
与
配对。
可以先尝试计算一下 可能的上界。对于每一个二进制位,若
中的所有数字在该位上 “
” 的个数之和大于 “
” 的个数之和,则显然无法通过配对使所有的 “
” 都被利用上(也就是说,肯定要“浪费”至少一个
),例如有三个数
,那么在二进制的第
位上有
个 “
” ,
个 “
” 。又由于所有数字是
的排列,故该位上 “
” 的个数之和至多比 “
” 的个数之和大
。综上,
的一个上界为
减去所有满足条件( “
” 的个数之和大于 “
” 的个数之和)的二进制位的值。
存在多种能达到这种答案上界的构造方法,以下介绍其中相对简单的一种。
若 表示当前需要考虑
中各个数字对应的
值,令
为
(以
的最高位)取反后的值:
-
若
不为
,则对于
范围内的每一个数
,令
。而后,令
;
-
若
为
,则
。而后,令
;
反复执行以上过程直到 为
即可。
T5时锁·封印
在本篇题解中作以下约定:最终答案指要求输出的答案,选取子串指最终答案在进行循环排列之前的结果,最大字符指输入的字符串中字典序最大的字符,连续段指由若干最大字符组成的子串。
根据本题的要求,想要找到字典序最大的答案,需要优先考虑最大字符。不难理解,最终答案的开头一定是最大字符。
先进行一个分类讨论:
假设存在若干由最大字符组成的连续段(比如样例中的 就存在
和
两个连续段)。由于可以进行循环排列,故选取子串的首尾一定是恰好两个连续段。因为这样可以使最终答案的开头由更多的最大字符构成。
假设仅存在一个由最大字符组成的连续段,那么它一定在选取子串中。
关键观察:最长的(如果存在同样长的则取最靠后的)连续段,一定会出现在最终答案中。
证明:如果不存在同样长度的连续段,则结论显然成立;如果存在同样长度的连续段,采用反证法,若选取子串不包含最长且最靠后的连续段,那么选取子串的首尾一定都是同样长度的连续段,此时若将尾部延伸至最靠后的连续段,等价于在最终答案之后添加了一段字符,根据字典序的定义,不如选取最靠后的连续段更优。
于是,我们可以根据上述分类讨论进一步研究实现方法:
如果存在若干由最大字符组成的连续段,那么最靠后的最长连续段一定是选取子串的开头或结尾。若在开头,则将该连续段之后的整个子串截取出来,再寻找一次最靠后的最长连续段作为选取子串的结尾即可。若在结尾,则将该连续段之前的子串截取出来,则问题等价于选取一个最大的后缀。可以在 复杂度完成或使用后缀数组在
的复杂度内完成。两种情况取字典序最大值即可。
如果仅存在一个由最大字符组成的连续段,则先将该连续段之前的子串截取出来,仍然选取一个最大的后缀。而后,再将该连续段之后的子串截取出来,逐个枚举并添加前缀字符,直到该字符小于前述后缀的开头字符即可。需要留意边界情况。
总时间复杂度和空间复杂度均为 。
T6时殒·残篇
将内层的两个求和看作一个整体,即先计算 。不难发现,对于每个
,存在唯一的
使得
。其实际意义是将集合
划分为若干个互不相交的子集
,由于
的唯一性,所有
的并集即为
,做到了遍历所有的
。因此,
,原式化为
。
令 ,原式变为
。把
,并令
(易知若
则答案为
),条件
等价于
且
。于是问题变为
把 的不同质因子列出来(设其数量为
)。利用容斥原理,把
的求和转换为对质因子子集的枚举:
对任意由质因子子集对应的乘积 ,令符号为
,则
把 ,得到我们需要计算的核心子问题:对某个
和上界
(这里
,
),求
因此总体算法流程是枚举所有子集(最多 ,对于
,
),对每个子集计算一次
并按符号累加。
对固定的 ,函数
是关于
的一个多项式,次数为
。有
公式:
其中系数 可通过伯努利数
来写成显式形式。常用形式为
因此若已知系数 ,对某个
:
把它代入 :
于是问题变为:对于每个 计算
。
直接用上面的 公式计算
(用伯努利数)对单个
是
的,若对所有
都做则是
每个
。我们需要把对每个
的计算批量化并尽可能加速。
利用伯努利数可得:
把此式按 取所有
,我们可把“对所有
的运算”组织成一个卷积问题,从而用
(模
的原根适合
)把复杂度降到
。
首先需要预先计算伯努利数序列 ,采用
递推或
生成函数的方法均可。
令序列
则卷积 在下标
上等于
取 ,得到
于是
所以只要做一次长度约 的卷积(
)就能同时得到所有
(
)。
因为对于不同的子集我们会遇到不同的 (但数量
上界为子集数
),我们对每个不同
做一次上述
并缓存结果,避免重复计算。
总体时间复杂度: 。