abc 234 ~ 237 题解
abc 234 e
题意
一个整数 \(n\) 被称为等差数需要满足以下条件:
-
令 \(n = \overline {d_1 d_2 \cdots d_k}\),且序列 \((d_1, d_2, \dots, d_n)\) 是等差数列。
-
若 \(n\) 是一位数,那么它也是等差数。
请你求出不小于 \(X\) 的最小等差数。
思路
首先,这个题目判断一个数是不是等差数的做法是很明显的:根据前两位求出公差 \(D\),判断后面的所有 \(d_i\) 是否都满足 \(d_{i - 1} + D\)。
那么,这里可以发现,我们要判断一个数是否为等差数,最重要的两个东西就是 \(d_1\) 和公差 \(D\),于是,可以发现,拥有了这两个东西就可以构造一个等差数了。
那么,做法就显而易见了:
枚举所有的公差与最高位,构造出等差数,求所有大于 \(X\) 的等差数的最小值。
abc 235 d
题意
现在给定一个 \(a\) 和一个操作数 \(X\),有两种操作:
-
将 \(X\) 乘 \(a\)。
-
将 \(X\) 看做成字符串,把 \(X\) 循环右移一位(\(X \ge 10\) 且 \(X\) 不被 \(10\) 整除)。
最开始 \(X = 1\),请问最少需要多少次操作可以使得 \(X\) 变为 \(N\)。
如果不能变成 \(N\),输出 \(-1\)。
思路
我们可以将每种操作看作成一条边,那么其实就是求从 \(1\) 到 \(N\) 的最短路,可以用 bfs
。
但是,这道题目还有一个比较有趣的点,它可以用记忆化搜索。
因为它有一个循环右移的操作,所以如果不停的做操作 2,就会构成一个环,但是这个环上的边必定有一条是不会走的,不然就会浪费,所以这是一张有向无环图,带有拓扑序。
abc 235 e
题意
给定一个 \(n\) 个点,\(m\) 条边的无向连通图,每条边有权值 \(c_i\),各不相同。
有 \(q\) 次询问,每次给出一条边:\(x_i, y_i, w_i\)
表示两端点为 \(x_i\) 和 \(y_i\) ,权值为 \(w_i\)
问:加入这条边之后,这条边是否会在新的最小生成树中?
思路
离线
因为你需要查询这条边是否在新的最小生成树中,所以有这么一种做法:
-
将原本的 \(m\) 条边和查询的 \(q\) 条边一起按照权值从小到大排序。
-
用并查集维护最小生成树,如果当前边是查询边,就查询两个点现在是否连通,如果是原来的边,就直接按照最小生成树的做法写。
在线
其实,你要查询一条边是否在最小生成树上,就是看这条边是不是在这两个点联通之前就被枚举到了。
也就是比较这两个点之间的简单路径上的边权的最大值和这条边的权值的大小就可以了。
abc 236 e
题意
\(n\) 个数 \(a_{1} \dots a_n\) 排成一列。现在要选出一些数,满足 任意两个相邻的数中至少有一个数被选择。
请求出:
-
所有选择方案中,被选中的数字平均值的最大值,误差在 \(10 ^ {-3}\) 以内视为正确;
-
所有选择方案中,被选中的数字中位数的的最大值。在这里,偶数 \(2k\) 个数的中位数视作第 \(k\) 小的数。
-
\(2 \le n \le 10 ^ 5\)
-
\(1 \le a_i \le 10 ^ 9\)
思路
二分 + dp
平均值
二分平均值(实数二分),\(Check(x)\) 表示平均值为 \(x\) 是否合法。
所以,我们设选择的数的下标为 \(p_1, p_2, \dots , p_k\),那么就有:
所以,\(b_i = a_i - x\),\(dp_i\) 表示子序列末尾为 \(b_i\) 的满足要求的子序列的最大子序列和。
那么有转移:\(dp_i = \max(dp_{i - 1}, dp_{i - 2}) + b_i\)。
中位数
二分中位数(整数二分),\(Check(x)\) 表示中位数为 \(x\) 是否合法。
我们将小于 \(x\) 的数都看做成 \(-1\),大于等于 \(x\) 的数看作 \(1\),用序列 \(b\) 记录这些映射后的值。
如果要使得中位数可以是 \(x\),就是使得满足要求的子序列的和大于 \(0\)。
那么,\(dp_i\) 为以 \(b_i\) 结尾的满足要求的子序列的最大子序列和。
所以就有转移:\(dp_i = \max(dp_{i - 1}, dp_{i - 2}) + b_i\)。
abc 236 f
题意
有 \(2 ^ N - 1\) 个数字,分别编号为 \(1, 2, \dots, 2 ^ N - 1\),想获得编号为 \(i\) 的数字需要支付 \(c_i\) 的代价。
现在你可以从这些数字中选出一些数,使得你可以通过某些数的编号的异或和来表示出 \([1, 2 ^ N - 1]\) 中的所有数。
请你求出最少需要支付多少代价。
思路
贪心。
首先,我们可以想到这样一种做法:
-
因为想要让支付的代价最少,所以将所有的 \(c_i\) 从小到大排序。
-
如果当前的这个 \(i\) 已经被标记过了,那么也就说明当前的 \(i\) 可以被别的数凑出来,那么就直接跳过。否则,将 \(i\) 和其他已经被标记过的元素取一次异或和所得到的值标记,并标记 \(i\),累加和。
那么,时间复杂度是多少呢?
总共有 \(2 ^ N - 1\) 个元素,每次枚举被标记过的元素最多需要 \(2 ^ N - 1\) 次。
总时间复杂度为 \(O(2 ^ {2 \times N})\),肯定会超时。
但是,真的是这样的吗?
时间复杂度分析
我们将排序后的序列 \(c\) 对应的编号记作 \(p_1, p_2, \dots, p_{2 ^ N - 1}\),当前选的元素的编号集合为 \(S\)。
当枚举到第 \(i\) 个元素时,若当前通过 \(S\) 凑出了 \(a_1, a_2, \dots a_k\),并且 \(p_i\) 不在 \(a_1, a_2, \dots, a_k\) 中,那么如果在 \(S\) 中加入 \(p_i\),可以得到与 \(a_1, a_2, \dots, a_k\) 均不同的 \(p_i, p_i \oplus a_1, \dots, p_i \oplus a_k\)。
假设 \(p_i \oplus a_1\) 在 \(a_1, a_2, \dots, a_k\) 中,存在 \(x_1, x_2, \dots, x_m \in S\),\(x_1 \oplus x_2 \oplus \dots \oplus x_m = p_i \oplus a_1\)。
则 \(x_1 \oplus x_2 \oplus \dots \oplus x_m \oplus a_1 = p_i \in \{a_1, a_2, \dots, a_k\}\),但是 \(p_i \notin \{a_1, a_2, \dots, a_k\}\)。
所以每一次往 \(S\) 中添加一个元素,\(S\) 中的元素数量会变成原来的两倍,而 \(S\) 中最后只有 \(2 ^ N - 1\) 个元素,也就意味着最多加入 \(n\) 个元素。
而加入 \(n\) 个元素肯定是可以凑出 \([1, 2 ^ N - 1]\) 的,我们可以直接选择 \(1, 2, 4, 8, 16 \dots 2 ^ N - 1\)。
那么,时间复杂度为 \(O(N \times 2 ^ N)\)。
贪心最优性证明
我们需要证明这样两个事情:
-
若当前 \(p_i\) 可以被凑出,不选 \(p_i\)。
-
若当前不能凑出 \(p_i\),选择 \(p_i\) 是最优的。
先证明第一点:
令最终选出的数所构成的集合为 \(S'\),那么 \(\forall z \in \{1, 2, \dots, 2 ^ N - 1\}\),都有 \(x_1 \oplus x_2 \oplus \dots \oplus x_m = z(x_1, x_2, \dots, x_m \in S')\)。
如果 \(x_1, x_2, \dots, x_m\) 中有一个数为 \(p_i\),我们不妨令这个数为 \(x_1\)。
那么 \(z = p_i \oplus x_2 \oplus \dots \oplus x_m\)。
因为 \(p_i\) 可以被凑出,所以 \(\exists y_1, y_2, \dots, y_k \in S\),且 \(p_i = y_1 \oplus y_2 \oplus \dots \oplus y_k\),则 \(z = y_1 \oplus \dots \oplus y_k \oplus x_2 \oplus \dots \oplus x_m\)。
所以,可以证明,\(z\) 不用 \(p_i\) 凑出。
接下来证明第二点:
令 \(C(S)\) 表示 \(\sum \limits _ {i \in S} c_i\)。
假设 \(p_i\) 不在 \(S'\) 时(\(p_i \notin S'\)),\(C(S')\) 是最优的。
则 \(\forall x_1, x_2, \dots, x_m \in S'\),且 \(p_i = x_1 \oplus x_2 \oplus \dots \oplus x_m\)。
由于当前用 \(S\) 中的元素凑不出 \(p_i\),那么说明,\(x_1, x_2, \dots, x_m\) 中至少有一个元素不属于 \(S\),不妨假设这个元素为 \(x_1\),也就是 \(x_1 \notin S\)。
\(\forall z \in \{1, 2, \dots, 2 ^ N - 1\}\),\(\exists y_1, \dots, y_k \in S'\),且 \(z = y_1 \oplus y_2 \oplus \dots \oplus y_k\)。
如果 \(y_1, y_2, \dots, y_k\) 中有一个为 \(x_1\),不妨设 \(y_1 = x_1\)。
也就是说 \(z = x_1 \oplus y_2 \oplus \dots \oplus y_k = p_i \oplus x_2 \oplus \dots \oplus x_m \oplus y_2 \oplus \dots \oplus y_k\)。
所以如果集合 \(S'\) 中去掉 \(x_1\) 并加上 \(p_i\) 也是合法的。
因为 \(x_1 \notin S\),所以 \(C_{x_1} \ge C_{p_i}\),则 \(C(S')\) 并不一定是最优的。
abc 237 f
题意
请你求出满足以下要求的序列数量,答案对 \(998244353\) 取模:
-
序列长度为 \(N\)。
-
序列中的每个整数都是 \([1, M]\) 内的一个数。
-
序列的最长上升子序列的长度恰好为 \(3\)。
\(1 \le N \le 1000\)
\(3 \le M \le 10\)
思路
首先,我们考虑暴力:搜出所有有可能的序列,判断最长上升子序列的长度是否为 \(3\),总时间复杂度为 \(O(N ^ {M + 2})\),很显然,是会超时的。
所以,应该怎么优化呢?
其实可以发现,在这道题目中,组成这个长度为 \(3\) 的最长上升子序列的那 \(3\) 个数是很重要的。
所以,我们可以考虑从这三个数入手。
\(dp_{i, a, b, c}\) 表示前 \(i\) 个数中的最长上升子序列的 \(3\) 个数分别为 \(a, b, c\) 的方案数。
那么就有转移(扩散型):