T1

100%

如果 TT 正好是某一班车的发车时刻,那么答案就是 00。否则,设 TT 距离最近的上一班车还差 r=(TS)modKr=(T-S)\bmod K,那么还需要等待的时间就是 KrK-r。把这两种情况合并起来,答案可以写成:

(K(TS)modK)modK(K-(T-S)\bmod K)\bmod K

直接按这个式子计算即可,当然也可以用 if 语句进行分类讨论。

时间复杂度 O(1)O(1)

T2

100%

由于题目保证只有 [说明] 的两侧有括号,因此从左到右扫描字符串,找到第一个 [ 和第一个 ] 的位置,输出中间的子串即可。

时间复杂度 O(s)O(|s|)

T3

100%

设原串中 0 的个数为 c0c_01 的个数为 c1c_1。最终要求两者数量相同,所以最少需要修改的字符数 kk 为:

k=c0c12k = \frac{|c_0-c_1|}{2}

接下来考虑字典序最小。

  • 如果 0 的数量更多,那么需要把一部分 0 改成 1。为了让字典序尽量小,应该尽量保留前面的 0,所以选择修改最靠右kk0
  • 如果 1 的数量更多,那么需要把一部分 1 改成 0。为了让字典序尽量小,应该尽量让前面变成 0,所以选择修改最靠左kk1

因此只需统计两种字符的数量,再按上述规则从左或从右挑出需要修改的位置即可(但输出下标时,需要从左往右输出)。

时间复杂度 O(n)O(n)

T4

100%

这是一个树上自底向上的贪心。

题目要求对任意祖先 uu 和后代 vv,满足最终高度 hu>hvh_u>h_v。由于我们只能让高度增加,所以一个节点最终至少要比它所有儿子的最终高度都大 1。也就是说,如果一个节点 uu 的儿子中的最终高度最高的是 HH,那么这个节点 uu 最终至少要变成 H+1H+1;如果它原本更大,则不需要额外修改,即:

hu=max(hu,maxvson(u)hv+1)h_u=\max\Bigl(h_u,\max_{v\in son(u)} h_v+1\Bigr)

因此,从根节点开始做后序 DFS:

  • 先递归处理所有子节点;
  • 取所有子节点最终高度的最大值 HH
  • 当前节点最终高度应当更新为 max(hu,H+1)\max(h_u, H+1)
  • 需要执行的操作次数就是这个新值减去原值,累加到答案里。

这样处理后,当前节点会自动满足“比所有后代都高”,并且对子树以外的部分没有额外影响,因此这是最优的。

时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)

T5

100%

为了击败邪教徒,我们至少需要总共打出 nd=HPSnd = \left\lceil \frac{HP}{S} \right\rceil 张打击牌。

接下来考虑如何在保证总打击牌数至少为 ndnd 的前提下,让机宝剩余血量尽可能多。

对于每一回合,我们贪心地尽可能打出多的打击牌。

具体来说,第 ii 回合打出 U=min(ui,ki)U=\min(u_i, k_i) 张打击牌,剩余的牌全部用于防御,即 V=min(vi,kiU)V=\min(v_i, k_i-U)。此时该回合机宝受到的伤害是 max(wiV×D,0)\max(w_i-V \times D, 0)

如果按照这个贪心策略打到某一回合,机宝的总打击牌数超过了 ndnd,且承受的总伤害没有让机宝死亡,那么超出的打击牌其实就是“冗余”的。我们可以把这些冗余的打击牌“撤回”,替换成防御牌,从而进一步减少受到的伤害,提高最终剩余血量

当我们将一张打击牌改为防御牌时(即反悔操作),该回合防御值增加 DD。观察伤害 max(wiV×D,0)\max(w_i-V \times D, 0)VV 的增加,减小量(即反悔收益)有两阶段特征:

如果当前 V×D<wiV \times D < w_i (即该回合收到伤害了):

  1. 在伤害降为 0 之前,每多 1 张防御牌,伤害稳定减少 DD
  2. 当伤害即将从 R=wimodDR=w_i \mod D 降至 0 时,这 1 张防御牌,只能减少 RR 点伤害。

由于每个回合可选的反悔操作的收益是单调不增的(先是若干个 DD,再是至多一个 RR,最后都是 0),因此我们可以使用 大根堆(优先队列) 来维护所有可用的反悔操作。

具体流程:

  1. 初始化:计算必须打出的打击牌数量 nd=HPSnd = \left\lceil \frac{HP}{S} \right\rceil。维护当前打出的打击牌总数 cntcnt,和当前累计受到伤害 damagedamage
  2. 模拟每一回合的操作:
    • 贪心打出 U=min(ui,ki)U=\min(u_i,k_i) 张打击牌,V=min(kiU,vi)V=\min(k_i-U,v_i) 张防御牌。
    • cnt+=Ucnt+=Udamage+=max(wiV×D,0)damage+=\max(w_i-V \times D,0)
    • 如果当前回合防御牌未打满(V<viV<v_i),且仍在掉血(V×D<wiV \times D < w_i),计算可反悔的次数和收益,压入大根堆(按收益从大到小排序):
      • 可反悔操作首先受打击牌和防御牌数量的限制,即 can=min(U,viV)can=\min(U,v_i-V)
      • 实际受到伤害为 get=wiV×Dget = w_i-V \times D,因此收益为 DD 的次数 numnumgetD\left\lfloor \frac{get}{D} \right\rfloor,压入大根堆。
      • can>numcan > numwimodD0w_i \mod D \neq 0,说明还可以有一次收益为 wimodDw_i \mod D 的操作,压入大根堆。
    • 反悔过程:只要当前总打击牌数量 cnt>ndcnt > nd 且堆不为空,说明我们有冗余的打击牌可以用来反悔。弹出堆顶操作(收益 valval,次数 numnum),将尽可能多的打击牌换成防御牌,并更新 cntcntdamagedamage
    • 若在某一回合的调整结束后,damage<hpdamage < hp(机宝存活)且 cntndcnt \geq nd,说明当前是一种可行的获胜状态,更新最大剩余血量。
  3. 输出最大剩余血量或 -1

时间复杂度约为 O(nlogn)O(n\log n)

T6

100%

我们需要计算:

$$S = \sum_{a' \in \mathrm{perm}(a)} \sum_{b' \in \mathrm{perm}(b)} F(a', b')$$

其中

$$F(x, y) = \sum_{1 \le i_1 < \dots < i_m \le n} \prod_{j=1}^{m} x_{i_j}^{y_j}.$$

FF 代入并交换求和顺序:

$$S = \sum_{a'} \sum_{b'} \sum_{1 \le i_1 < \dots < i_m \le n} \prod_{j=1}^{m} (a'_{i_j})^{b'_j}.$$

重新组织求和:对于固定的 aa 的大小为 mm 的子序列(保持原下标顺序),以及固定的 bb 的一种排列,计算这些值在所有 aa' 中出现多少次。

  • aa 中选出 mm 个元素,并按选出的顺序放入子序列位置,有 P(n,m)=n!(nm)!P(n, m) = \frac{n!}{(n-m)!} 种方式。
  • aa 中剩余的 nmn-m 个元素可以任意排列在剩下的位置上,有 (nm)!(n-m)! 种方式。
  • 两者相乘,表示每种“有序的 mm 元子序列 + 剩余元素排列”恰好对应一个完整的 aa',出现次数为 P(n,m)×(nm)!=n!P(n,m) \times (n-m)! = n!

因此,bb' 取遍所有 m!m! 种排列,而 aa' 的求和可以转化为对 aa 的所有大小为 mm 的有序子序列求和,再乘上 n!n!

$$S = n! \sum_{1 \le i_1 < \dots < i_m \le n} \sum_{b' \in \mathrm{perm}(b)} \prod_{j=1}^{m} a_{i_j}^{b'_j}.$$

这样我们就把问题分解为两部分:

  • 计算 $T = \sum_{1 \le i_1 < \dots < i_m \le n} \sum_{b' \in \mathrm{perm}(b)} \prod_{j=1}^{m} a_{i_j}^{b'_j}$;
  • 最终答案 S=n!TS = n! \cdot T

其中 TT 的含义是:在序列 aa 中按原顺序挑选 mm 个元素构成子序列,同时将 bb 的所有排列作为指数分配给这些元素,求所有乘积之和。

这可以通过动态规划解决。我们按顺序遍历 aa 的每个元素,并逐步决定它是否被选入子序列,以及如果被选中,它对应 bb 中的哪一个指数。为了不重不漏地枚举 bb 的所有排列,我们还需要记录 bb 中哪些位置已经被分配,由于 m10m \leq 10,因此可以通过二进制状态来表示。

状态定义: 用二进制掩码 mask\mathrm{mask} 表示当前已经使用了 bb 中的哪些元素(0mask<2m0 \le \mathrm{mask} < 2^m)。
dp[mask]\mathrm{dp}[\mathrm{mask}] 表示在当前已经考虑过的 aa 的前缀中,选出的子序列已经占用了 mask\mathrm{mask} 中的 bb 元素时,所有合法方案的乘积之和。

转移: 顺序遍历 aa 中的每个元素 aia_i(代码中保持原始顺序)。对于当前的 aia_i,我们有两种选择:

  1. 不选 aia_idp[mask]\mathrm{dp}[\mathrm{mask}] 保持不变。
  2. aia_i,并把它分配给 bb 中某个尚未使用的指数 bjb_jjmaskj \notin \mathrm{mask}): 此时新状态为 mask{j}\mathrm{mask} \cup \{j\},贡献要乘上 aibja_i^{b_j}

写成递推式,对于当前 aia_i

$$\mathrm{new\_dp}[\mathrm{mask}] = \mathrm{dp}[\mathrm{mask}] + \sum_{j \in \mathrm{mask}} \mathrm{dp}[\mathrm{mask} \setminus \{j\}] \cdot a_i^{b_j}$$

其中 jmaskj \in \mathrm{mask} 等价于“在上一步状态 mask{j}\mathrm{mask} \setminus \{j\} 的基础上,选用 aia_i 并匹配 bjb_j”。

初始化: 未考虑任何 aa 元素时,空集状态乘积为 11dp[0]=1\mathrm{dp}[0] = 1,其余为 00

最终结果: 处理完 aa 的全部 nn 个元素后,dp[(1m)1]\mathrm{dp}[(1 \ll m) - 1] 即为所需的 TT——它恰好枚举了所有大小为 mmaa 子序列,以及 bb 的所有排列与之匹配的情况。

由前面的推导,答案即为:

$$S = n! \cdot \mathrm{dp}[(1 \ll m) - 1] \bmod 998244353.$$

时间复杂度为 O(nm2m)O(nm2^m)(幂运算可以提前 O(nmlogV)O(nm \log V) 预处理并保存到数组中),空间复杂度为 O(2m)O(2^m)(滚动数组优化空间,否则为 O(n2m)O(n2^m))。

0 comments

No comments so far...