最近一些题的题解瞎口胡(22年暑假)

1. 摩尔庄园

用树形 dp 模拟网络流。

\(a\)\(x\) 走向 \(fa(x)\) 的次数,\(b\)\(fa(x)\) 走向 \(x\) 的次数,\(flw(x) = a - b\)

这样在从 \(x\) 走向 \(fa\) 时:

  • 如果 \(flw(x) < 0\),表示有更多次从 \(fa\) 走向 \(x\),那么这一次费用为 \(-1\),表示和之前一次从 \(fa\) 走向 \(x\) 的费用抵消了(网络流的思路)。
  • 否则,无法抵消,费用为 \(1\)

\(fa\) 走向 \(x\) 时是类似的。

从下往上进行 \(\rm Update\),计算从 \(x\) 到其子树中有食物的地方,费用最小是多少,并记录下那个点的编号。

每读入一只拉姆的位置,就计算其费用并更新图中的费用。

Code

2. Centroids

CF708C Centroids

一个优秀的性质是以重心为根时所有点的子树大小都不会超过 \(\dfrac{n}{2}\),因为根本身就是如此。

对于节点 \(u\),这时只有 \(u\) 上面的部分有可能超过 \(\dfrac{n}{2}\),那么最优策略是选择其中最大的不超过 \(\dfrac{n}{2}\) 的子树,把它接到 \(u\) 上,设这一部分的大小为 \(cut_u\),那么剩下的部分就是 \(n - siz_u - cut_u\),如果仍然大于 \(\dfrac{n}{2}\),那么无法成为重心;否则可以。

于是问题转为如何求 \(cut_u\)

记录 \(mx_u\)\(u\) 子树内(不包括 \(u\))最大的不超过 \(\dfrac{n}{2}\) 的子树大小,当从 \(u\) 转移到 \(v\) 时:

\[cut_u = \cases { \max(cut_u, n - siz_u), n - siz_u \le \dfrac{n}{2} \\ cut_u, \rm otherwise } \\ cut_v = \max(cut_u, mx_u) \]

但如果 \(v\) 的子树就是 \(u\) 的最大的不超过 \(\dfrac{n}{2}\) 的子树,这时 \(mx_u\) 是不能选的,所以我们应该记录最大值和次大值 \(mx_{u,0}, mx_{u, 1}\)。这样转移就变成了

\[cnt_v = \cases { \max(cut_u, mx_{u, 0}), siz_v \ne mx_{u, 0} \\ \max(cut_u, mx_{u, 1}), siz_v = mx_{u, 0} } \]

Code

3. 由乃与大母神原型和偶像崇拜

P3792 由乃与大母神原型和偶像崇拜

发现 \(n\) 个数的和容易重,但平方和就不好重。所以维护区间最小 \(mn\)、区间最大 \(mx\)、区间和 \(sum1\)、区间平方和 \(sum2\)

首先判断 \(mn + len - 1\) 是否等于 \(mx\),然后求 \(\sum\limits_{i = mn}^{mx} i\) 是否等于 \(sum1\)\(\sum\limits_{i = mn}^{mx}i ^2\) 是否等于 \(sum2\)

模数直接 $\rm unsigned\ long\ long $ 自然溢出,注意等差数列与平方和都要除一个数,把它乘到式子另一边去。

当然你怕不保险也可以加上立方和,这样就几乎卡不掉了(

Code

4. Book of Evil

CF337D Book of Evil

记录 \(mx_{u, 0}\)\(mx_{u, 1}\) 分别表示 \(u\) 到子树内的 damage 的最大和次大距离,且保证二者 不在同一条到 \(u\) 的路径上(即 不在同一分支),\(dis_u\) 表示 \(u\) 到子树外的 damage 的最大距离。三个数组的初始值均为 \(-\infty\);特别地,当 \(u\) 节点本身存在 damage 时,\(mx_{u,0}\)\(mx_{u, 1}\) 有初始值 \(0\)

\(mx\) 的更新比较显然:(\(v\in \{son_u\}\)

  • \(mx_{v,0} + 1 > mx_{u, 0}\) 时,次大值变为 \(mx_{u, 0}\),同时让 \(mx_{v, 0} + 1\) 作为新的最大值;注意最大值和次大值不能在同一分支上,所以不用 \(mx_{v, 1}\) 再去更新次大值。
  • 否则,\(mx_{u, 1} \gets \max(mx_{u, 1}, mx_{v, 0} + 1)\)

第二遍 Dfs,计算 \(dis\) 值:

  • 如果 \(mx_{v, 0} + 1 = mx_{u, 0}\),则最大值在 \(v\) 的子树内,不能用来计算,\(dis_v \gets \max(dis_u,mx_{u, 1}) + 1\)
  • 否则 \(dis_v \gets \max(dis_u, mx_{u, 0}) +1\)

最后判断 \(\max(mx_{u, 0}, dis_u)\) 是否 \(\le d\) 即可。

Code

5. Valid Sets

CF486D Valid Sets

定义连通图的代表点为图内权值最大的点,若有多个点权值相等则取编号最小者。

那么每一个连通图都必然 有且只有一个 代表点,我们枚举这个代表点 \(rt\),求出满足要求且以 \(rt\) 为代表点的连通图数量,这样就能保证不重不漏。

具体地,以 \(rt\) 为根开始 Dfs,设 \(dp_u\) 表示在 \(u\) 的子树内,包含节点 \(u\),且代表点为 \(rt\) 的满足要求的连通图数量,初始值为 \(1\)(只选 \(u\))。

当从节点 \(u\) 到其子节点 \(v\) 时,先判断 \(v\) 的加入是否仍满足 \(rt\) 是代表点,如果不是,\(dp_u\) 不变,否则递归进入 \(v\) 的子树,回溯后,\(v\) 的子树的连通块可选可不选,

\[dp_u \gets dp_u (1 + dp_v) \]

最后,以 \(rt\) 为代表点的数量就是 \(dp_{rt}\),将所有加起来即是答案。

Code

6. Snuke Line

AT2300 [ARC068C] Snuke Line

对于一个 \(d\),如果其存在 \([l, r]\) 的倍数,则必存在正整数 \(k\),使得

\[l\le dk \le r \\ \left\lceil\dfrac{l}{d}\right\rceil \le k \le \left\lfloor\dfrac{r}{d}\right\rfloor \\ \left\lfloor\dfrac{l - 1}{d}\right\rfloor < k \le \left\lfloor\dfrac{r}{d}\right\rfloor \]

所以只要找到所有 \(d\),满足

\[\left\lfloor\dfrac{l - 1}{d}\right\rfloor < \left\lfloor\dfrac{r}{d}\right\rfloor \]

一个一个枚举 \(d\) 是不行的,可以使用整除分块,对于 \(\left\lfloor\dfrac{l - 1}{d}\right\rfloor\)\(\left\lfloor\dfrac{r}{d}\right\rfloor\) 均相等的 \(d\),对它们的答案全部加 \(1\),具体可以用差分。这个整除分块的区间是 \([1, l - 1]\)

对于 \([l, r]\)\(d\)\(\left\lfloor\dfrac{l - 1}{d}\right\rfloor\) 必然为 \(0\),而 \(\left\lfloor\dfrac{r}{d}\right\rfloor\) 至少为 \(1\)

对于 \((r, +\infty)\)\(d\),二者的值均为 \(0\),不产生贡献。

总时间复杂度为 \(\Omicron(n\sqrt{m} + m)\)

Code

7. Addition and Subtraction Hard

AT2273 [ARC066C] Addition and Subtraction Hard

首先有一个很显然的性质:

  • 括号只添加在减法后。

推论:如果出现了两个减号,比如

\[13 - 9 - A \]

其中 \(A\) 为一个算式,那么第二个减号后,即 \(A\) 中的所有数都可以变成正数。

\[13 - 9 - 15 - 7 + 10 - 8 + 16 + 34 \]

可以变成

\[13 - (9 - 15 - (7 + 10) - (8 + 16 + 34)) \]

除了第二个减号前的 \(9\),其它数全部负负得正成了正数。

所以第一个减号前的数不用动,第一个和第二个减号之间的数全部取反,后面的数全部取正,加起来即是答案。我们所需要做的就是枚举这第一个括号的位置,注意最后还要和不加括号比较。

Code

8. Phoenix and Computers

CF1515E Phoenix and Computers

最后会形成类似 一段手动 + 一个自动 + 一段手动 + …… + 一段手动 的情形。

\(dp_{i, j}\) 表示共有 \(i\) 个手动,\(j\) 段手动的开灯方案数,转移方程如下:

\[dp_{i + 1, j + 1} \gets dp_{i + 1, j + 1} + dp_{i, j}\cdot (j + 1) \\ dp_{i + 1, j} \gets dp_{i + 1, j} + dp_{i, j} \cdot 2j \]

其中新开一段可以在其余 \(j\) 段中插 \((j + 1)\) 个空,而不新开一段则在原来 \(j\) 段中挑头或尾开灯共 \(2j\) 种。

最后只有满足 \(i + j - 1 = n\) 的才能产生贡献,因为全部点亮时必定满足 手动个数 + 自动个数 = 总灯数,而自动个数恰为 \((j - 1)\)

Code

9. 萌萌哒

P3295 [SCOI2016]萌萌哒

朴素做法是将 \([l1, r1]\) 中每个点分别和 \([l2, r2]\) 中对应的点并入一个集合,设最后共有 \(k\) 个集合,那么每个集合内都为同一个数,则 \(ans = 9 \cdot 10^{k - 1}\)(首位不为 \(0\)),时间复杂度为 \(\Omicron(n^2\alpha(n))\)

使用倍增进行优化,设并查集中 \(fa_{i, k}\) 表示以 \(i\) 为左端点的长度为 \(2^k\) 的区间 \([i, i + 2^k - 1]\) 所在的集合的根区间的左端点,比如 \(l_1 = 1, r_1 = 4, l_2 = 5, r_2 = 8\),将区间 \([1, 4]\) 并到 \([5, 8]\) 所在的集合,那么此时 \(fa_{1, 2} = 5\)

对于一个区间长度为 \(len\) 的区间,直接对 \(len\) 进行二进制拆分处理,比如 \(l_1 = 1, r_1 = 3, l_2 = 4, r_2 = 6\),那么 \(len = 3 = (11)_2\),分别令 \(fa_{1, 1} \gets 4, fa_{3, 0} \gets 6\)

但是最后查询时是落实到单点上面,所以还需要一次下传,方法是将一个长度为 \(2^k\) 的区间断成两个长度为 \(2^{k - 1}\) 的区间,将两段分别与根的对应两段合并。

时间复杂度为 \(\Omicron(n\log n\cdot\alpha(n))\)

Code

posted @ 2022-05-26 14:16  mango09  阅读(35)  评论(0编辑  收藏  举报
-->