- 代码源挑战赛 Round 69
代码源挑战赛 Round 69 题解
- @ 2026-7-18 13:58:26
T1
100%
直接尽量多做“包装 瓶”的操作即可。设做了 次这种操作后,还剩下 瓶;剩余的每一瓶都只能单独包装,因此还需要 次操作。
所以答案就是:
$$\left\lfloor \frac{n}{x} \right\rfloor + n \bmod x $$时间复杂度 。
T2
100%
规则是:
P得分为 ,然后连击数加 ;G得分为 ,然后连击数加 ;M不得分,连击数清零。
因此只需要从左到右模拟一遍,记录当前连击数 combo、累计总分 ans 和历史最大连击数 mx:
- 遇到
P时,ans += combo + 300,再令combo++; - 遇到
G时,ans += combo + 100,再令combo++; - 遇到
M时,combo = 0。
每次更新后用 mx = max(mx, combo) 维护最大连击数即可。
最后输出 ans 和 mx。
时间复杂度 。
T3
100%
给定一个 串 和整数 ,统计满足 、、、且 的数对个数。
可以把它看成在长度不超过 的窗口内,统计每个 1 左边有多少个 0。
我们可以从左到右扫描字符串时,维护当前窗口内 0 的个数 cnt:
- 当前字符是
0,就把cnt++; - 当前字符是
1,就把当前窗口内的所有0都与它配对,因此答案加上cnt。 - 当右端点在位置 时,当前窗口为 ,下一个窗口为 ,因此需要位于 的字符:如 果 位置是
0,那么cnt--,否则cnt不变。
这样每个字符只进出窗口一次,整体就是一个长度为 的滑动窗口统计。
时间复杂度 。
T4
100%
由于强化牌会将后续所有的伤害牌进行强化,因此选出若干张手牌后,出牌的顺序一定是先打出所有强化牌,然后再打出所有伤害牌。
然后思考如何计算最终总伤害:设选中的强化牌的 之和为 ,选中的伤害牌的 之和为 ,每张伤害牌的伤害为 ,因此打出的总伤害为:
$$\sum_{\text{伤害牌}} x_i \times (1+S) = D \times (1+S) $$问题转化为我们需要在费用 内,选择一组强化牌(总费用 ,总加成 ),和一组伤害牌(总费用 ,总基础伤害和 ),最大化 ,且 。两类牌的选择是独立的,只有费用共享。
由于 ,我们可以对两类牌分别做 0/1 背包,再枚举费用分配求最优解。
设:
f[j]表示花费不超过 的前提下,所有伤害牌能获得的最大基础伤害和;g[j]表示花费不超过 的前提下,所有强化牌能获得的最大法术强度和。
两类牌分别做一次 0/1 背包:
- 若是伤害牌,就更新
f; - 若是强化牌,就更新
g。
最后枚举总费用分配:假设给强化牌分配了 点费用,那么伤害牌就分配 点费用,答案为:
需要注意乘积可能超过 32 位整型范围。
时间复杂度 ,空间复杂度 。
T5
100%
由于 ,我们可以 枚举所有连续子串并统计答案,但需要快速计算当前子串的 值。
设当前固定左端点为 ,向右枚举右端点 。固定左端点后,先令 now = -1(当子串只有一个字符时 ),并将每个字符第一次出现的位置数组清空。用 now 表示子串 的答案,当我们把右端点从 扩展到 时,有两种选择:
- 直接删除新字符
s[j],那么当前子串答案为now + 1; - 如果新字符
s[j]之前在子串 中出现过,则可以保留s[j],设第一次出现位置是p,那么可以保留从 到 的这一段,让首尾字符相同,此时需要删除的只有p前面那部分字符,答案为p - i。
于是新的答案可以更新为:
其中若当前字符 从未出现过,就只能删除该字符,令 。每个字符第一次出现的位置可以通过一个数组来记录:每次枚举一个左端点 时创建该数组,枚举 并更新 now 后,若 第一次出现,则更新数组。
每次更新后把 now 累加到答案中,就得到了所有子串的总和。
时间复杂度 。
T6
100%
我们首先分析两种操作:
对 的操作会同时给相邻两个位置加上同一个数,因此 的“奇偶位交替和”不变。设:
并且由于 可以取任意整数,且这种操作只会给相邻两个位置同时加上同一个值,所以它保留了交替和不变;反过来,也可以通过逐步调整相邻差分,把任意交替和等于 的序列互相变换,因此 可以通过操作变成任意一个交替和等于 的序列。
而对 的操作只是交换相邻元素,可以把 变成任意排列,并且总和不变,记为:
所以原问题等价于:是否存在一个 的排列,使得它的交替和恰好等于 。
当序列长度为 时,奇数位置有 个,如果我们从 中选出 个数放在奇数位置,它们的和为 ,那么放在偶数位置的数的和就是 。
此时整个序列的交替和为:
我们需要让交替和等于 :
化简得:
因此问题就变成:
- 从 中选出恰好 个数放到奇数位;
- 这些数的和是否能等于 。
如果 是奇数,显然无解,直接输出 No。
剩下就是一个“选固定个数、固定总和”的子集和问题,由于 ,如果暴力枚举所有组合,最多会有 种情况,无法通过题目,需要使用折半枚举的技巧:
- 把 数组分成前后两半;
- 枚举前半部分的所有子集,记录当前子集选了多少个数以及总和,记录到哈希表中;
- 再枚举后半部分的所有子集,在哈希表中检查是否存在一个子集,与前半子集合并后,使得总个数恰好是 ,总和恰好是目标值 。
只要存在一种这样的划分,就能通过相邻交换把 排成目标顺序,再利用 的操作把两边变成同一个数组。
时间复杂度约为 :左半枚举是 ,右半枚举也是 ;如果写法不当,可能会多乘一个 。每次左右合并可以做到 ,若用 map 或二分查找,则会多一个 的因子,因此这里更适合使用哈希表。