2024.5 做题记录

1. P8227 「Wdoi-5」建立与摧毁的结界

首先放到括号树上来考虑。
操作一就变成了将一条链上所有点都变成链顶的父亲的儿子,操作二就变成了将一个点的所有儿子拉成一条链。

对两棵树同时 dfs,那么我们只需要做两件事:把一棵子树全拍成一排点;递归求子树的答案。
所以双指针扫一遍即可。

需要的信息可以 dfs 一遍预处理。

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

2. CF1610H Squid Game

先考虑如果先强制选了一个点会发生什么。
如果钦定以这个点为根,那么所有有转折的路径一定都被干掉了,现在只需考虑所有的祖先连向后代的路径。
考虑把剩下的每条路径都挂到它的深度最浅的点上,这样就可以贪心处理。
具体地,对树进行 dfs,如果当前节点还有路径没有被消掉,就把能消掉这条路径的最浅的点选上。
这个可以用树状数组简单实现。
这样就得到了一个 \(O(n^2 \log n)\) 的点。

考虑不枚举第一次操作的点,随便找一个点当做根。
我们假装所有非祖先连向后代的路径都已经被干掉了,对于祖先连向后代的路径,我们同上面的方式处理。
然后再考虑非祖先连向后代的路径。

  • 如果它们都已被消掉,那么就可以直接输出答案。
  • 否则,我们需要再在根处操作一次,这样所有限制都满足了。

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

3. ABC276Ex Construct a Matrix

发现这个限制实际上就是限制了一些矩形存在 \(0\)、一些矩形没有 \(0\)、一些矩形中 \(2\) 的个数的奇偶性。
先把能填成 \(0\) 的全填成 \(0\),然后剩下的限制就都和 \(2\) 的个数的奇偶性相关了。

考虑把个数的奇偶性用异或来表示。
\(s_{i, j}\) 表示前 \(i\) 行前 \(j\) 列的 \(2\) 的个数的奇偶性,那么限制就是四个位置的异或和等于 \(0\)\(1\)

直接把有用的位置拉出来高斯消元即可。
时间复杂度 \(O(\frac{Q^3}{w})\)

4. P10107 [GDKOI2023 提高组] 树

向下倍增。设 \(f_{u, i}\) 表示从点 \(u\) 向下跳 \(2^i\) 步的所有点的答案。
可以在 bfs 序上考虑。

注意到合并的时候是和一个区间合并,所以记为前缀和的形式应该更加自然。
所以改为 \(f_{u, i}\) 表示从与点 \(u\) 同层且 bfs 序小于等于 \(u\) 的点向下跳 \(2^i\) 步的所有点的答案。
发现预处理这个还要维护 \(son_{u, i}\) 表示从点 \(u\) 向子树内跳 \(2^i\) 步后所处的 bfs 序最大的点、\(g_{0 / 1, u, i}\) 表示与点 \(u\) 同层且 bfs 序小于等于 \(u\) 的点的所有子树内第 \(i\) 位为 \(0 / 1\) 的点的个数。

然后直接倍增即可,询问的时候要查分掉 \(u\) 同层的前一个点的贡献。
想好细节再写。
时间复杂度 \(O((n + q) \log n)\)

5. P3850 [TJOI2007] 书架

傻逼平衡树,一点营养没有。

6. CF1876E Ball-Stackable

首先考虑没有边定向的做法。
一定是定向成一棵外向树,然后每条边染成不同的颜色,答案为 \(n - 1\)

然后对于有边定向了的情况可以想枚举哪个点当根,然后把能定位外向边的边全定为外向边,染色就是 dfs 一遍,维护根链的颜色的栈,内向边就弹栈,外向边就染色。
对于栈为空是仍要弹栈的情况,不难发现是不优的,因为可以把根移到栈空的那个点。

时间复杂度线性。

7. P2487 [SDOI2011] 拦截导弹

可以转化为求以每个位置开始和结束的最长不升子序列的长度和个数。
然后限制是二维偏序,套个 CDQ 优化 dp 转移就做完了。
时间复杂度 \(O(n \log^2 n)\)

8. P4690 [Ynoi2016] 镜中的昆虫

只有二操作是二维数点。
一操作可以通过维护颜色连续段的形式转化成单点改,所以是带修二维数点,CDQ 即可。
时间复杂度 \(O(n \log^2 n)\)

9. ABC313Ex Group Photo

不妨设 \(a_{0} = a_{n + 1} = + \infty\)

先考虑判定方法。
判定的话就是分别将 \(\min(a_i, a_{i - 1})\)\(b\) 排序,然后依次判定。

考虑将 \(a\) 从大到小加入,那么当前的 \(\min(a_i, a_{i - 1})\) 就是 \(a_i\)
当前已经填完的 \(a\) 形成了若干个连续段,所以直接连续段 dp。

\(f_{i, j}\) 表示考虑了前 \(i\) 大的 \(a\),形成了 \(b\) 条链的方案数。
转移就是分类讨论:

  • \(a_i\) 单独成为一条新的链:\(f_{i, j} \times (j - 1) \rightarrow f_{i + 1,j + 1}\)
  • \(a_i\) 连到已有的链的两端:\(f_{i, j} \times (2j - 2) \rightarrow f_{i + 1, j}\),此时需满足 \(a_{i} < b_{i +1 - j}\)
  • \(a_i\) 连接已有的两条链:\(f_{i, j} \times (j - 1) \rightarrow f_{i + 1, j + 1}\),此时需满足 \(a_i < b_{i - j}\)

时间复杂度 \(O(n^2)\)

10. ARC171E Rookhopper's Tour

首先发现 \(m\) 只有是不为 2 的偶数时才可能有解。
因为若 \(m\) 为奇数,那么第一次和最后一次移动都在同一行或同一列上,一定是错的。

然后最直接的想法就是对每行每列建一个点,然后将所有白子的横坐标向纵坐标连边,这样一次移动就是找到一个和当前的边有相同端点的边,跳到这条边上,然后再向远的方向跳一步。
如图所示:

image

黑边是初始的边,跳的白子是绿色的那条边,跳完后是蓝色的那条边。

不妨设我们第一次跳到了一个横坐标相同的白点,那么有:

  • \(2n\) 个白子和第 \(2n + 1\) 个白子的横坐标相同,纵坐标相邻。
  • \(2n + 1\) 个白子和第 \(2n + 2\) 个白子的纵坐标相同,横坐标相邻。

发现实际上横纵坐标的方案数是独立的,都是类似于若干个 \((x, x + 1)\) 的 pair 的形式。
还可以对于一种白子的摆放方法,它的跳法实际上是唯一的,这个可以归纳证明。
所以第一步跳到横坐标相同的白子的方案数和第一步跳到纵坐标相同的白子的方案数是互不干扰且相同的。
所以问题就等价为了选 \(\frac{m}{2}\)\((x, x + 1)\) 形式的 pair。

不妨设下面的讨论都是基于第一步跳了纵坐标相同的点(总方案数乘以 2 即可)。
不妨设选了 \((A, A + 1)\)(选 \((A - 1, A)\) 的情况是类似的)。

枚举 \([1, A)\) 选的 pair 的数量是 \(i\),那么 \((A + 1, n]\) 选的 pair 数就是 \(j = m - i - 1\)
那么选出 pair 的方案数就是 \(\binom{A - 1 - i}{i} \times \binom{n - A - j}{j}\)

然后要解决访问顺序的问题。
因为最后一步一定走的是 \((A, A + 1)\) 这个 pair,所以倒数第二步一定是从 \((A + 1, n]\) 中的一个 pair,所以这部分的方案数即为 \(j \times (m - 2)!\)

相乘即为答案。

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

11. P9480 [NOI2023] 深搜

问题可以转化为:求选非树边的方案数使得对于选了的每条非树边都存在关键点使得它是返祖边。

显然是要容斥的。
\(cnt_S\) 表示选择 \(S\) 中的关键点为根时返祖边的数量,答案为:

\[\sum_{S \neq \varnothing} (-1)^{\lvert S \rvert + 1} 2^{cnt_S} \]

直接暴力是 \(2^kn\) 的。

先考虑若固定了一个关键点集合 \(S\),什么样的非树边不能够被选中。
不妨在 \(S\) 的虚树上考虑。

  • 若根节点被选中,那么不能被选的非树边有以下几种:
    • 横叉边;
    • 跨过黑点或白点;
    • 从非虚树上点的子树中延伸到虚树上。
  • 若根节点没有被选中,那么不能选的非树边大致于上一种情况相似,但横叉边有一种特例是可以被选的:
    • 若根节点只有 \(2\) 个儿子 且 此条横叉边两端点的 \(\text{lca}\) 恰好为根 且 两端点之间的路径上没有被选中的点。

然后考虑 dp。设 \(f_u\) 表示只考虑以 \(u\) 的虚树时代容斥系数的方案数之和。
不妨先考虑没有横叉边的情况。
事实上我们发现我们还需要记 \(dp_{0 / 1 / 2}\) 表示选了 \(0 / 1 / \ge 2\) 个儿子时的方案数,以应对点 \(u\) 没有被选中的情况。
此时有:

  • \(u\) 为关键点:\(f_u = dp_2 - dp_0 - dp_1 - dp_2 = - dp_0 - dp_1\)
  • \(u\) 不是关键点:\(f_u = dp_2\)

现在只用考虑求 \(dp\) 数组。
考虑类似背包的方式,依次把每个子树选成儿子与不选成儿子的贡献加入,那么我们需要动态维护子树的贡献。
子树中点的贡献的变化是好维护的,对于一条返祖边,把它所在的子树的贡献 \(\times 2\) 即可,查贡献就是 dfn 上的区间和。
线段树维护区间乘区间和即可。
父亲部分与不选当前子树的贡献可以简单预处理得出。

然后再考虑有横叉边的情况,先把横叉边存到端点的 lca 上。
发现我们只有根没有被选成关键点且恰好选了 2 个儿子时答案才会算错,所以只需计算这部分的贡献即可。
先把每个子树的贡献乘上不选它的贡献的逆元,这样就只有选了的子树之间才会产生贡献。
考虑放到二维平面上,横坐标为第一个选的点,纵坐标为第二个选的点,点权为同时选这两个的贡献,这样横叉边的贡献就成了矩形乘 2,根没有被选成关键点且恰好选了 2 个儿子时的贡献就是平面求和再减掉两个点选到同一棵子树的贡献,这个是可以提前减掉的。

这样就做完了。
卡常的话可以换成链式前向星,把 dfn 记下来顺着 dfn 做等。
时间复杂度 \(O(n \log n)\)

12. CF1217E Sum Queries?

首先发现问题等价于求存在一位都不为 0 的两个数使得他们和最小,线段树维护即可。
时间复杂度 \(O(n \log n \log V)\)

13. CF576E Painting Edges

线段树分治,在叶子处决定下一次操作的颜色即可。
时间复杂度 \(O(n \log^2 n)\)

14. P4172 [WC2006] 水管局长

时光倒流,然后是 LCT 加边维护最小生成树板子。
时间复杂度 \(O(n \log n)\)

15. P3206 [HNOI2010] 城市建设

线段树分治,然后是 LCT 加边维护最小生成树板子,撤销是平凡的。
时间复杂度 \(O(n \log^2 n)\)

16. P4319 变化的道路

LCT 加边维护最小生成树板子。
时间复杂度 \(O(n \log n)\)

17. P8329 [ZJOI2022] 树

\(f(S)\) 为 第一棵树中选定 \(S\) 集合为叶子时的方案数,\(g(S)\) 为 第二棵树中选定 \(S\) 集合为叶子时的方案数。
那么答案为(\(U\) 为全集 \(\{1, 2, \cdots, n\}\)):

\[\sum_{S \cap T = \varnothing, S \cup T = U} f(S) \times g(T) \]

然后发现恰好为 \(S\) 的限制是 \(S\) 中的点一定不被连,\(U /\ S\) 中的点一定被连,这是困难的。
但是发现把恰好变为钦定就会少一个限制,就会简单很多。
所以设 \(F(S)\) 表示 第一棵树中钦定 \(S\) 集合为叶子时的方案数,\(g(S)\) 表示 第二棵树中钦定 \(S\) 集合为叶子时的方案数。
由子集反演可知:

\[f(S) = \sum_{S \subseteq T} (-1)^{\lvert T \rvert - \lvert S \rvert} F(T) \]

\[g(S) = \sum_{S \subseteq T} (-1)^{\lvert T \rvert - \lvert S \rvert} G(T) \]

那么答案就变成了:

\[\begin{aligned} ans &= \sum_{S \cap T = \varnothing, S \cup T = U} \left( \sum_{S \subseteq S'} (-1)^{\lvert S' \rvert - \lvert S \rvert} F(S') \right) \times \left( \sum_{T \subseteq T'} (-1)^{\lvert T' \rvert - \lvert T \rvert} G(T') \right) \\ &= \sum_{S \cap T = \varnothing, S \cup T = U} \sum_{S \subseteq S', T \subseteq T'} (-1)^{\lvert S' \rvert +\lvert T' \rvert - n} F(S') \times G(T') \\ &= \sum_{S \cup T = U} (-1)^{\lvert S \rvert + \lvert T \rvert - n} F(S) \times G(T) \end{aligned}\]

然后就能做了。设 \(f_{i, j, k}\) 表示 已经给 \([1, i]\) 选好了父亲,第一棵树的 \([1, i]\) 钦定了 \(j\) 个叶子节点,第二棵树的 \((i, n]\) 钦定了 \(k\) 个叶子节点 时的方案数,转移是平凡的。

但发现如果这样对每个 \(n\) 求答案的话是 \(O(n^4)\) 的。
所以考虑把状态改为表示有多少个点没被钦定成叶子,这样就好了。
时间复杂度 \(O(n^3)\)

18. P5163 WD与地图

先时光倒流,变成加边。
考虑求出每条边被缩掉的时间,这样求答案就是扫一遍线段树合并啥的做一做。

发现答案有可二分性,不妨考虑一下整体二分。
现在问题就变成了有一个边集,求在一个时间 \(mid\) 前哪条边会被缩。这可以想到把出现时间 \(\le mid\) 的点加到如中跑缩点,然后就能分出左右两个集合,分别递归求解即可。
为了保证时间复杂度,可以在递归右侧时把在同一个强联通分量里的点缩起来,然后对边的端点用强联通分量中的一个代表点的编号重编号即可。

时间复杂度 \(O(m \log V)\)

19. CF1613F Tree Coloring

先把限制容斥掉,变成钦定 \(k\) 个节点满足限制,容斥系数为 \((-1)^k\)
不妨记这个为 \(f(k)\)

发现一个父亲最多钦定一个儿子,所以这些钦定的节点组成了若干条链。
现在问题变成了:有一些链,链上的点要求颜色为父亲的颜色减一,不在链上的点颜色无要求,节点颜色互不相同,求方案数。

不妨设钦定了 \(k\) 个点。
先看没被钦定的点的方案数:我们把同一条链上的颜色看成一段,这样就有 \(n - i\) 段颜色,方案数为 \((n - i)!\)
再看被钦定了的点的方案数:每个点可以选择一个儿子作为钦定的点,所以方案数为 \([x^k] \prod_{u = 1}^n (1 + son_u)\)

分治 NTT 即可,时间复杂度 \(O(n \log^2 n)\),有多种方式优化成 \(O(n \log n)\)

20. P2567 [SCOI2010] 幸运数字

首先把询问差分成 \([1, r] - [1, l - 1]\),现在只需考虑形如 \([1, n]\) 的询问。

容斥一下,变成枚举一个非空集合 \(S\),求 \([1, n]\) 中是 \(\operatorname{lcm}(S)\) 的倍数的数的个数,容斥系数是 \((-1)^{\lvert S \rvert + 1}\)

打标发现,有用的数只有 \(943\) 个,此时时间复杂度为 \(2^{943}\) 级别的,无法通过。
有以下几个剪枝:

  • 在当前 \(\operatorname{lcm}(S) > n\) 时直接 break。
  • 将有用的数倒序排序,使 \(lcm\) 增长更快。

然后就能过了。

21. #4361. isn

给你一个长为 \(n\) 的序列,重复进行以下操作直至序列不降:

  • 选择一个数,把它从序列中删除。
    求不同的操作方案的数量。

\(n \le 2 \times 10^3\)

第一想法是求长度为 \(i\) 的不降子序列的个数 \(f_i\),然后答案为 \(f_i \times (n - i)!\),但这显然是错的。
考虑它为什么错,就是如果我们在序列长为 \(i\) 之前就把序列删成了不降的,那么后面的操作都是不合法的。
不妨强制让它删到长度为 \(i\),然后考虑如果要让这次操作不合法,最后一步删除一定在长度为 \(l + 1\) 的不降子序列中删了一个数。
所以答案为 \(\sum_{i = 1}^n f_i \times (n - i)! - f_{i + 1} \times (l + 1) \times (n - i - 1)!\)

\(f_i\) 可以通过树状数组优化 dp 的方式求出。
时间复杂度 \(O(n^2 \log n)\)

22. #3269. 序列染色

给你一个长为 \(n\) 的序列,每个位置有 \(0\)\(1\)\(2\) 这三种权值,权值为 \(0\) 的位置会变成 \(1\)\(2\)
求有多少种变化后的序列满足:存在两个不交的长为 \(k\) 的区间 \([l_1, r_1], [l_2, r_2] (l_1 < l_2)\)\(a_{[l_1, r_1]}\) 中全是 1,\(a_{[l_2, r_2]}\) 中全是 2。
\(n \le 10^6, k\le 10^6\)

考虑找一种不会算重的方式:对于所有长为 \(k\) 且全是 1 的区间,我们去最靠前的一个;对于所有长为 \(k\) 且全是 2 的区间,我们取最靠后的一个。这样一个序列就对应着唯一的区间选择方式。

如果我们能计算出 \(f_{i}\) 表示 使得 \([i - k + 1, i]\) 为全是 1 的最靠前的区间的方案数,\(g_{i}\) 表示 使得 \([i, i + k - 1]\) 为全是 2 的最靠后的区间的方案数,就能计算出答案:

\[ans = \sum_{i < j} f_i \times g_j \times 2^{cnt_{[i + 1, j - 1]}} \]

其中 \(cnt_{[l, r]}\) 表示 区间 \([l, r]\) 中 0 的个数。

先考虑求 \(f\)

我们可以用 \((i - k, i]\) 全是 1 的方案数减去 \((i - k, i]\) 中的 1 不是最靠前的的方案数。
不难列出转移方程:

\[f_{i} \leftarrow 2^{cnt_{[1, i - k]}} - \sum_{j = k}^{i - 1} f_j \times 2^{cnt_{[j + 1, i - k]}} \]

用变量分别维护 \(j \in [1, i - k - 1]\)\(j \in [i - k, i]\) 中的转移就可以做到 \(O(1)\) 转移。

\(g\) 的求法是类似的。

然后考虑统计答案。
扫描线,记当前扫的位置为 \(i\),用变量维护 \(sum = \sum_{j < i} f_j \times 2^{cnt_{[j + 1, i - 1]}}\),用 \(sum \times g_i\) 更新答案即可。

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

posted @ 2024-05-29 11:06  definieren  阅读(33)  评论(0)    收藏  举报