联合省选 2021 B 卷题解

Day1

数对

给定 \(n\) 个正整数 \(a_i\),请你求出有多少个数对 \((i, j)\) 满足 \(1 \le i \le n\)\(1 \le j \le n\)\(i \ne j\)\(a_i\)\(a_j\) 的倍数。

\(2 \le n \le 2\times 10^5\)\(1 \le a_i \le 5 \times 10^5\)

考虑使用桶,记 \(cnt_x\) 表示 \(a_i = x\) 的个数。

那么分两种情况讨论,第一种情况是 \(a_i = a_j = x\),对答案的贡献为 \(\sum \binom{cnt_x}{2}\);第二种是 \(a_i = x < a_j = y\),那么这时候枚举 \(a_i\) 的值 \(x\),同时枚举 \(x\) 的倍数 \(y\),对答案的贡献为 \(\sum\limits_{x} \sum\limits_{y} cnt_x cnt_y\)

时间复杂度是经典的调和级数 \(O(\frac{n}{1} + \frac{n}{2} + \frac{n}{3} + \cdots) = O(n \ln n)\)

卡牌游戏

\(n\) 张卡牌,第 \(i\) 张卡牌的正面有数字 \(a_i\),背面有数字 \(b_i\),初始时所有卡牌正面朝上。

现在可以将不超过 \(m\) 张卡牌翻面,最小化朝上的 \(n\) 个数字的极差。

\(3 \le n \le 10^6\)\(1 \le m < n\)\(1 \le a_i, b_i \le 10^9\)\(a_i\) 单调不下降,\(2n\) 个数字互不相同。

先把 \(a, b\) 拼成一个长度为 \(2n\) 的数组 \(c\) 排序。

对于这个有序的数组,极差即是选中的那一段 \(l, r\)\(c_r-c_l\)

于是用双指针枚举 \(l, r\),不在 \(l, r\) 当中则意味着那一位被删除,具体要求是:

  • 删掉的 \(a\) 面不超过 \(m\)
  • 不存在同一张卡牌的 \(a, b\) 面同时被删除。

对于第一条开一个 \(cnt\) 维护,第二条开一个 \(vis\) 数组维护即可。

时间复杂度 \(O(n \log n)\),不明白 \(a\) 有序有什么意义。

图函数

对于一张 \(n\) 个点 \(m\) 条边的有向图 \(G\),定义函数 \(f(u, G)\)

  • 初始化返回值 \(cnt = 0\),图 \(G' = G\)
  • \(1\)\(n\) 按顺序枚举顶点 \(v\),如果当前的图 \(G'\) 中,从 \(u\)\(v\) 与从 \(v\)\(u\) 的路径都存在,则将 \(cnt + 1\),并在图 \(G'\) 中删去顶点 \(v\) 以及与它相关的边。
  • \(2\) 步结束后,返回值 \(cnt\) 即为函数值。

现在给定一张有向图 \(G\),请你求出 \(h(G) = f(1, G) + f(2, G) + \cdots + f(n, G)\) 的值。

更进一步地,记删除(按输入顺序给出的)第 \(1\)\(i\) 条边后的图为 \(G_i\),请你求出所有 \(h(G_i)\) 的值。

\(2 \le n \le 10^3\)\(1 \le m \le 2 \times 10^5\)\(1 \le x_i, y_i \le n\),没有重边和自环。

因为只要求求出每个 \(h(G_i)\),而不是求具体的 \(f(u, G_i)\),所以考虑贡献法。

考虑一对 \((u, v)\) 如果能对 \(f(u, G_i)\) 造成贡献,当且仅当存在一条 \(u \to v \to u\) 的环,且这个环上没有编号 \(<v\) 的点。

于是问题转化为对于 \(\forall G_i\),求 \(G_i\) 中有多少 \((u, v)\)\(u \ge v\))满足存在 \(u \to v \to u\) 的环不经过编号 \(< v\) 的点。

一个点对显然会对一个 \(G\) 的前缀造成贡献,令 \(path(u, v)\) 表示最大化的 \(u \to v\) 的路径上经过的边的编号的最小值。那么 \(G_{1 \sim \min(path(u, v), path(v, u))}\) 会得到贡献。

可以直接 Floyd \(O(n^3 + m)\) 或 Dijkstra \(O(nm \log m)\) 求出。

当然这不稳,可以考虑一个更高明的做法。枚举 \(v\),在每张图中只保留 \([v, n]\) 那些点,求出每张图中它能到达的点的个数即可。

当然直接这样模拟是 \(O(nm^2)\) 的,考虑反转时间轴变成逆序加边,对于一条新加的边 \((a, b)\)\(a, b \ge v\)):

  • 如果 \(vis_a = 1\)\(vis_b = 0\),那么从 \(b\) 开始 BFS;
  • 如果 \(vis_a = 0\)\(vis_b = 0\),那么先加到图中,等着以后可能有用;
  • 否则这条边没有意义。

易证每一条边最多只会用到一次,所以在 BFS 的时候“过河拆桥”即可。时间复杂度 \(O(nm)\)

Day2

取模

给定 \(n\) 个正整数 \(a_i\) 请你在其中选出三个数 \(i, j, k\)\(i \ne j\)\(i \ne k\)\(j \ne k\)),使得 \((a_i + a_j) \bmod a_k\) 的值最大。

\(3 \le n \le 2 \times 10^5\)\(1 \le a_i \le 10^8\)

首先将 \(a\) 数组排序,逆序枚举 \(a_k\),在前面做二分或者双指针求出 \((a_i + a_j) \bmod a_k\) 的最大值更新答案。

\(ans \ge a_k\) 的时候就可以 break 了,可以证明枚举的 \(a_k\) 的个数是 \(\log\) 级别的,但我不会证

宝石

给定一棵大小为 \(n\) 的树以及 \(m\) 种宝石,结点 \(i\) 上有第 \(w_i\) 种宝石。

宝石收集顺序是一个长度为 \(c\) 的序列 \(P\)\(P\) 中没有重复元素。

\(q\) 次询问,每次给出 \(s, t\),问从 \(s\) 走到 \(t\) 的过程中,所经过的结点的 \(w\) 形成的序列与 \(P\) 的最长公共子序列的长度。

\(1 \le n, q \le 2 \times 10^5\)\(1 \le c, m \le 5 \times 10^4\)\(1 \le P_i, w_i \le m\)

\(s \to t\) 拆为 \(s \to \text{lca}, \text{lca} \to t\) 的两个过程。

考虑链上的情况,记结点 \(u\) 的后继 \(suc_{u}\) 为其右边最近的满足 \(w_v\)\(P\) 序列中恰好是 \(w_u\) 的下一项的 \(v\)

那么如果询问的 \(s < t\),就从 \(s\) 右边的第一个 \(w = P_1\) 的位置开始,不断跳 \(suc\),直到越过 \(t\) 结束,跳的次数就是询问的答案。不难发现这个过程可以倍增优化。

现在搬到树上,\(s \to \text{lca}\) 的过程不难套用上述方法,但如果考虑 \(\text{lca} \to t\) 呢?

一个解决办法是把过程拟过来,记录 \(pre_{u}\) 为其父亲链上的最近的满足 \(w_v\)\(P\) 序列中恰好是 \(w_u\) 的前一项的 \(v\)

每次询问的时候二分答案 \(a\),从 \(t\) 上方的最近的 \(w = P_a\) 的那一个位置开始不断跳 \(pre\) 就行了。

至于找到“\(t\) 上方的最近的 \(w = P_x\) 的位置”,可以使用可持久化线段树维护这个东西。

时间复杂度 \(O(q \log^2 m)\)

滚榜

给定一个长度为 \(n\) 的数组 \(a\),求有多少 \(1 \sim n\) 的排列 \(p\),满足存在一个 \(\sum b = m\) 的不下降序列 \(b\),使得对于任意 \(i, j\)\(i < j\)),都有:

  • \(a_{p_j} + b_{p_j} \ge a_{p_i} + b_{p_i} + [p_i < p_j]\)
  • \(a_{p_i} + b_{p_i} \ge a_{p_j} + [p_j < p_i]\)

\(1 \le n \le 13\)\(1 \le m \le 500\)\(0 \le a_i \le 10^4\)

容易发现 \(b\) 的分配是贪心的,每次给出最小的 \(b\),只要 \(\sum b \le m\) 就是合法的方案。

一个显然的结论是“当前选手想当 rank 1 只要比上一名选手高即可”,这是因为上一名选手是当前的 rank 1。

于是可得(忽略编号问题,这个显然是容易处理的):

  • 如果 \(a_i \ge a_{i - 1}\),则 \(b_i = b_{i - 1}\)
  • 如果 \(a_i < a_{i - 1}\),则 \(b_i = b_{i - 1} + a_i - a_{i - 1}\)

综合一下上面两个式子其实就是 \(b_{i} = b_{i - 1} + \max(0, a_i - a_{i - 1})\)

进而通过考虑贡献可以知道 \(\sum b = \sum \max(0, a_i - a_{i - 1}) (n - i + 1)\)(每个贡献都是一个后缀)。

于是考虑状压 DP,用 \(f(S, i, j)\) 表示,当前使用过的集合是 \(S\),最后一个选的是 \(i\),以及当前对 \(\sum b\) 的贡献是 \(j\)。转移的时候枚举接下来选哪一个人,计算一下贡献即可。

时间复杂度 \(O(2^n n^2 m)\),轻微卡常。

posted @ 2021-04-13 23:08  syksykCCC  阅读(1347)  评论(5编辑  收藏  举报