2017 Multi-University Training Contest 1 solutions BY 北京航空航天大学

1001. Add More Zero

答案就是 $\left \lfloor \log_{10}(2^m - 1) \right \rfloor$,注意到不存在 $10^k = 2^m$ ,所以$\left \lfloor \log_{10}(2^m - 1) \right \rfloor = \left \lfloor \log_{10}{2^m} \right \rfloor = \left \lfloor m \log_{10}{2} \right \rfloor$,这样做的时间复杂度是 O(1) 。

1002. Balala Power!

每个字符对答案的贡献都可以看作一个 26 进制的数字,问题相当于要给这些贡献加一个 0 到 25 的权重使得答案最大。最大的数匹配 25,次大的数匹配 24,依次类推。排序后这样依次贪心即可,唯一注意的是不能出现前导 0。

1003. Colorful Tree

单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和。反过来思考只需要求有多少条路径没有经过这种颜色即可。直接做可以采用虚树的思想(不用真正建出来),对每种颜色的点按照 dfs 序列排个序,就能求出这些点把原来的树划分成的块的大小。这个过程实际上可以直接一次 dfs 求出。

1004. Division Game

显然每个石子堆最多做 $\sum_{i = 1}^{m}{e_i}$ (记为 $w$ )次操作。此外,如果定义一个堆做 $x$ 次操作恰好变为 $1$ 的方案数为 $f(x)$ ,显然每个数字做少于 $x$ 次操作不变为 $1$ 的方案数也是 $f(x)$ 。 为了统计结束于石子堆 $i$ 的情况数,我们可以枚举这是它第几次操作时结束的,不妨设为 $x$ ,则对应的方案数恰好是 $f(x + 1)^{i - 1} f(x)^{k - i + 1}$ ,因为编号小于等于 $i$ 的石子堆做了 $x$ 次操作不变为,其他石子堆做 $x - 1$ 次操作恰好变为 $1$ ,且只有石子堆 $i$ 变成了一个石子。因此我们在 O(w k) 时间复杂度下将问题规约到 $f(x)$ 的计算。 我们可以基于一个数的不同质因子几乎互不影响的观察得到第一个结论。每次操作保证任何一个 $e_i$ $(e_i > 0)$ 可以减少且至少一个 $e_i$ 会减少。自然而然我们可以发现一个容斥关系。 考虑 $f(x)$ 的组成,不妨设在某种方案中第 $j$ 次操作使 $e_i$ 减少了 $d(i, j)$ (非负值)。我们知道对于每个 $e_i$ 有 $\sum_{j = 1}^{x}{d(i, j)} = e_i$ ,且对于每个 $j$ 有 $\sum_{i = 1}^{m}{d(i, j)} > 0$ 。进一步我们能发现 $f(x)$ 也就是分配 $d(i, j)$ $(1 \leq i \leq m, 1 \leq j \leq x)$ 使其满足上述两个条件的方案数。 假设只满足第一个条件的相应方案数为 $g(x)$ ,我们可以发现每个 $i$ 分别对应一个组合问题,从而是有 $\displaystyle g(x) = \prod_{i = 1}^{m}{e_i + x - 1 \choose x - 1}$ 。 我们也可以观察到如果某些 $j$ 与第二个条件产生了矛盾,与之相关的 $d(i, j)$ 都会是零。利用容斥原理可以得到 $\displaystyle f(x) = \sum_{y = 0}^{x}{(-1)^{x - y} {x \choose y} g(y)}$ 。这个式子可以化为一个卷积式子 $\displaystyle \frac{f(x)}{x!} = \sum_{y = 0}^{x}{\frac{(-1)^{x - y}}{(x - y)!} \cdot \frac{g(y)}{y!}}$ 。因此你可以用一些方法来加速卷积,不过 $985661441 = 235 \times 2^{22} + 1$ 是一个特殊的质数,所以我们推荐使用 NTT 。 总时间复杂度为 O(w m + $w \log n$ + w k),然而实现上谨慎一些也是很有必要的。

1005. Expectation Division

解决这道题需要观察到一些比较经典的结论。在分析前我们先两组与题目相关的定义:对于任意正整数的质因子分解 $n = \prod_{i = 1}^{k}{p_i^{e_i}}$ ,定义 $\omega(n) = k$ 表示 $n$ 的不同质因子个数, $\sigma(n) = \sum_{d | n}{1} = \sum_{i = 1}^{k}{(e_i + 1)}$ 表示 $n$ 的约数个数,显然有 $2^{\omega(n)} \leq \sigma(n)$ 。 这题本来是为 OI 赛制的比赛准备的,然而没有被使用。接下来会根据几个部分分给出做法,希望能对大家有所启发。 对于 $n \leq 10^6$ 的数据: 题目中所表述的过程是一个标准马尔可夫过程,所以我们可以用 $f(n)$ 表示使用这种操作把 $n$ 变成 $1$ 的期望试验次数,并且我们可以得到 $f(1) = 0,$ $\displaystyle f(n) = \frac{\sum_{d | n}{f(d)}}{\sum_{d | n}{1}} + 1$ ,化简后为 $\displaystyle f(n) = \frac{\sigma(n) + \sum_{d | n, d < n}{f(d)}}{\sigma(n) - 1}$ 。 很容易计算出满足 $n \in N^{+},$ $n \leq N$ 的所有 $f(n)$ ,复杂度为 O($\sum_{n \leq N}{\sigma(n)}) = O(N\log N)$ ,这里不再赘述。 对于 $n \leq 10^{12}$ 的数据: 直接在线为每个询问计算答案是有些不现实的,这里给出一个考虑不同数字之间的关系并记忆化存储信息的做法。 首先观察到,对于 $n = \prod_{i = 1}^{k}{p_i^{e_i}},$ $m = \prod_{i=1}^{k'}{{p'_i}^{e'_i}}$ ,如果 $k = k'$ 并且对于 $i = 1, 2, \cdots, k$ 都有 $e_i = e'_i$ (适当地安排质因子的顺序之后),那么我们可以得到 $f(n) = f(m)$ ,这与具体的 $p_i, p'_i$ 是多少无关。 不妨将每个数字对应的 $e_1, e_2, \cdots, e_k$ 按非升序排序,可以观察到将这些幂指数的集合拿出来并去重后剩下集合的数量不会很多。对于一个集合 $e_1, e_2, \cdots, e_k$ (满足非升序),我们可以构造出可能的最小值 $n = 2^{e_1} 3^{e_2} 5^{e_3} 7^{e_4} \cdots$ ,而且可以大致估计出不超过 $N$ 的本质不同的幂指数的集合个数不会超过 $\log N$ 的分拆数数量,再利用搜索就可以确定实际的数量了,例如 $N = 10^{12}$ 时本质不同的集合个数为 $4357$ 。 事实上当 $n \leq 10^{12}$ 时,我们可以观察到 $\sigma(n) \leq 6720$ ,于是每次询问时将 $n$ 映射到其幂指数的集合上,利用记忆化搜索的技巧枚举约数即可以单次 O($\sigma(n))$ 的复杂度通过测试数据。 对于 $n \leq 10^{18}$ 的数据: 之前的方法难以奏效,因为现在有 $\sigma(n) \leq 103680$ 并且本质不同的集合个数达到 $32749$ 个。 为了观察更细致一些,我们定义 $g(n) = \sum_{d | n}{f(d)}$ ,记忆化搜索时先计算出满足 $d | n, d < n$ 的所有 $f(d), g(d)$ ,然后依次计算出 $g'(n) = \sum_{d | n, d < n}{f(d)},$ $f(n) = \frac{\sigma(n) + g'(n)}{\sigma(n) - 1},$ $g(n) = g'(n) + f(n)$ 。 尝试优化计算 $g'(n)$ 的过程,也即计算中的瓶颈部分。如果改用容斥的技巧,我们有 $\displaystyle g'(n) = \sum_{T \subseteq S}{(-1)^{|T| + 1} g\left(\frac{n}{\prod_{p_i \in T}{p_i}}\right)}$ ,其中 $S = \{p_i | i = 1, 2, \cdots, k\}$ ,这样可以使单次运算的复杂度从 $O(\sigma(n))$ 降到了 $O(2^{\omega(n)})$ 。 类似地,当 $n \leq 10^{18}$ 时,我们可以观察到 $\omega(n) \leq 15$ ,所以这个优化在实际运算中已经足以通过 $n \leq 10^{18}$ 的数据。 [b]对于 $n \leq 10^{24}$ 的数据:[/b] 上述做法再次不适用了,因为现在本质不同的集合个数达到 $172513$ 个,并且有 $2^{\omega(n)} \leq 2^{18} \leq 262144$ ,因此我们需要再次进行优化。 考虑 $g(n)$ 的组成,所有满足 $d = \prod_{i = 1}^{k}{{p_i}^{t_i}}$ 且对于 $i = 1, 2, \cdots, k$ 有 $0 \leq t_i \leq e_i$ 的 $d$ 都会对 $g(n)$ 贡献一个 $f(d)$ ,这本质上是 $k$ 维前缀和。 参考大小为 $k$ 的二进制子集求和(经典问题),我们可以定义 $g_x(n)$ 表示对于 $i = 1, 2, \cdots, x$ 有 $0 \leq t_i \leq e_i$ 且对于 $i = x + 1, x + 2, \cdots, k$ 有 $t_i = e_i$ 的 $f(d)$ 之和,而考虑 $i = x$ 时 $0 \leq t_i < e_i$ 和 $t_i = e_i$ 这两种情况,不难得到 $g_x(n)$ 可以用 $g_{x - 1}(n)$ 和 $g_y(\frac{n}{p_x})$ 表示,其中 $y$ 取决于 $\frac{n}{p_x}$ 是否依旧能整除 $p_x$ 。这个方法可以将时间复杂度降低至每次 $O(\omega(n))$ 。 注意这个做法具体结合到非升序的幂指数序列时可能要修改一下 $g_x(n)$ 的定义。 复杂度分析: 这道题的大数运算很容易在常数时间内实现。记忆化搜索时可以用 bitset 配合基数排序线性地对幂指数序列的排序,但是它是可以避免的(甚至是递归时的拷贝)。标程的时间复杂度与空间复杂度都是 $O((S(N) + T) \omega(N))$ ,其中 $S(N)$ 表示在不超过 $N$ 的正整数里出现的本质不同的集合个数 $(S(N) \leq 172513)$ , $T$ 表示数据组数,并且 $\omega(N) \leq 18$ 。

1006. Function

考虑置换 $a$ 的一个循环节,长度为 $l$ ,那么有 $f(i) = b_{f(a_i)} = b_{b_{f(a_{a_i})}} = \underbrace{b_{\cdots b_{f(i)}}}_{l\text{ times }b}$ 。 那么 $f(i)$ 的值在置换 $b$ 中所在的循环节的长度必须为 $l$ 的因数。 而如果 $f(i)$ 的值确定下来了,这个循环节的另外 $l - 1$ 个数的函数值也都确定下来了。 答案就是 $\sum_{i = 1}^{k} \sum_{j | l_i} {j \cdot cal_j}$ 改为 $\prod_{i = 1}^{k} \sum_{j | l_i} {j \cdot cal_j}$ ,其中 $k$ 是置换 $a$ 中循环节的个数, $l_i$ 表示置换 $a$ 中第 $i$ 个循环节的长度, $cal_j$ 表示置换 $b$ 中长度为 $j$ 的循环节的个数。 时间复杂度是 $\mathcal{O}(n + m)$ 。

1007. Gear Up

整个图的结构是一个森林,首先可以将共轴的齿轮看成一个块(它们角速度相同),再考虑共边的情况。 如果 $x$ 和 $y$ 共边, $x$ 的半径为 $r_x$ 、角速度为 $\omega_x$, $y$ 的半径为 $r_y$ 、角速度为 $\omega_y$ ,则可以知道 $\log\omega_y = \log\omega_x + \log r_x - \log r_y$ 。 由此可以得出每个连通分量中每个齿轮角速度与某个特定齿轮的关系,从而利用线段树维护齿轮(或块)的 dfs 序列对应的区间角速度最大值。具体来说,每个连通分量任选一个齿轮作为参照点,维护其他齿轮与其角速度的差值。每个连通分量可以看成是一棵有根树,当一个齿轮的半径发生变化时,根据其是 $r_x$ 还是 $r_y$ 分两种情况更新一段 dfs 序区间。查询时只需要得出对应连通分量中相对角速度的最大值,再与当前点的相对角速度进行对比即可算出实际的最大值。 具体实现中可以维护 $\log_2 \omega$ ,在输出时再转化为 $\log\omega$ 。

1008. Hints of sd0061

最慢的情况是 $b$ 的取值为 $0,$ $1,$ $2,$ $3,$ $5,$ $8,$ $\cdots$ 的情况,但事实上也只有 $\mathcal{O}(\log_{1.618}{n})$ 个取值。 从最大的取值到最小的取值依次使用近似线性复杂度的求第 $k$ 小的方法即可,该方法的思想与快排相似,可以保证前 $k - 1$ 小的元素都放置在第 $k$ 小元素的前面,这样枚举的时候就可以依次减少每次的枚举量,时间复杂度 $\displaystyle\mathcal{O}\left(\sum_{i \geq 0}{\frac{n}{1.618^i}}\right) = \mathcal{O}(n)$ 。

1009. I Curse Myself

由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉。所以问题就变为有 $M$ 个集合,每个集合里面都有一堆数字,要从每个集合中选择一个恰好一个数加起来。求所有的这样的和中,前 $K$ 大的是哪些。这就是一个经典问题了。 对所有集合两个两个进行合并,设当前合并的集合是 $A$ 和 $B$,合并的过程中用堆来求出当前 $A_{i} + B_{j}$ 的前 $K$ 大值是哪些。这样的复杂度看起来为 $\mathcal{O}(MK \log K)$,但如果合并的时候保证堆内的元素个数是新集合里的元素个数,设每个集合的大小分别为 $m_{0}, m_{1}, \cdots, m_{M-1}$,则复杂度为 $\mathcal{O}(\sum{K \log{m_{i}}}) = \mathcal{O}(K \log{\prod{m_i}})$。当 $m_{i}$ 都相等时取得最大值 $\mathcal{O}\left(MK \log{\frac{\sum{m_i}}{M}}\right)$,所以实际复杂度为 $\mathcal{O}(MK)$。 事实上存在一个时间复杂度 $\mathcal{O}(MK)$ 直接暴力求解的算法,但需要空间复杂度较好,例如空间复杂度 $\mathcal{O}(K)$ 。

1010. Journey with Knapsack

标程的做法是生成函数。定义装满 $k$ 体积空间的食物有 $f(k)$ 种方案,对应的生成函数为 $F(z) = \sum_{k \geq 0}{f(k) z^k}$ 。如果我们可以确定多项式 $F(z) \bmod z^{2 n + 1}$ 的系数,那么枚举 $m$ 个装备的体积即可轻松算出答案。 根据乘法原理,第 $i$ 种食物对 $F(z)$ 贡献的因子是 $\displaystyle 1 + z^i + z^{2 i} + \cdots + z^{a_i i} = \frac{1 - z^{(a_i + 1) i}}{1 - z^i}$ ,因此 $\displaystyle F(z) = \prod_{i = 1}^{n}{\frac{1 - z^{(a_i + 1) i}}{1 - z^i}} = \prod_{i = 1}^{n}{\left(1 - z^{(a_i + 1) i}\right)} \prod_{i = 1}^{n}{\frac{1}{1 - z^i}}$ 。 由于 $0 \leq a_1 < a_2 < \cdots < a_n$ 的限制,我们知道对于 $i = 1, 2, \cdots, n$ 有 $a_i \geq i - 1$ ,也即 $(a_i + 1) i \geq i^2$ 。所以只有 $\mathcal{O}(\sqrt{n})$ 项 $\left(1 - z^{(a_i + 1) i}\right)$ 在模 $z^{2 n + 1}$ 意义下不为 $1$ 。你可以利用类似背包的动态规划 $\mathcal{O}(n \sqrt{n})$ 进行计数。 剩下的部分是 $\displaystyle \left(\prod_{i = 1}^{n}{\frac{1}{1 - z^i}}\right) \bmod z^{2 n + 1}$ ,这很像分拆数的生成函数。分拆数的生成函数被定义为 $P(z) = \sum_{k \geq 0}{p(k) z^k}$ ,其中 $p(k)$ 表示 $k$ 的本质不同的拆分数量。五边形数定理表明 $\displaystyle P(z) = 1 + \sum_{k \geq 1}{(-1)^k \left(z^{\frac{k (3 k + 1)}{2}} + z^{\frac{k (3 k - 1)}{2}}\right)}$ ,从而我们可以在需要的时候 $\mathcal{O}(m \sqrt{m})$ 计算出多项式 $P(z) \bmod z^m$ 。 回到原来的部分,我们做如下化简: $$\displaystyle{\prod_{i = 1}^{n}{\frac{1}{1 - z^i}} \equiv \prod_{i = n + 1}^{2 n}{(1 - z^i)} \prod_{i = 1}^{2 n}{\frac{1}{1 - z^i}} \equiv P(z) \prod_{i = n + 1}^{2 n}{(1 - z^i)} \equiv P(z) \left(1 - \sum_{i = n + 1}^{2 n}{z^i}\right) \pmod{z^{2 n + 1}}}$$ 上面的式子表明我们可以利用前缀和将其规约到 $P(z) \bmod z^{2 n + 1}$ 。总的时间复杂度为 $\mathcal{O}(n \sqrt{n})$ 。

1011. KazaQ's Socks

找规律即可。规律是 $\underbrace{1, 2, \cdots, n}_{n\text{ numbers}},$ $\underbrace{1, 2, \cdots, n - 1}_{n - 1\text{ numbers}},$ $\underbrace{1, 2, \cdots, n - 2, n}_{n - 1\text{ numbers}},$ $\underbrace{1, 2, \cdots, n - 1}_{n - 1\text{ numbers}},$ $\underbrace{1, 2, \cdots, n - 2, n}_{n - 1\text{ numbers}},$ $\cdots$ 。

1012. Limited Permutation

根据 $[l_i, r_i]$ $(1 \leq i \leq n)$ ,我们可以尝试线性地排序并建立一棵笛卡尔树,如果产生矛盾则答案为 $0$ 。 具体来说,我们可以依次找到能够覆盖整个区间 $[L, R]$ 的点 $u$ 。如果找不到则无解。如果找到多个,随便选一个,反正会在之后的决策中被中断。在这棵笛卡尔树上, $u$ 的左孩子(如果存在)应该能覆盖 $[L, u - 1]$ ,同理它的右孩子(如果存在)应该能覆盖 $[u + 1, R]$ ,这意味着我们可以固定区间的一个端点,排序另外一个端点得到孩子节点。最终我们可以建立一棵笛卡尔树。 若存在一棵笛卡尔树,则这棵笛卡尔树是唯一的。每棵子树都基于相似的子问题,所以我们只需要在合并子树时计算子树的组合即可。例如 $u$ 有两个儿子 $v_1$ 和 $v_2$ ,它们的子树对应的方案数分别为 $f(v_1)$ 和 $f(v_2)$ ,子树大小分别为 $s(v_1)$ 和 $s(v_2)$ ,则 $u$ 的子树对应的方案数为 $\displaystyle f(u) = {s(v_1) + s(v_2) \choose s(v_1)} \cdot f(v_1) \cdot f(v_2)$ 。 由于使用基数排序,故处理的时间复杂度为 $\mathcal{O}(n)$ ,主要时间还是花在了读入上面。我们可以加一些读入优化使得复杂度变成 $\mathcal{O}(n \log_{10}{n})$ ,其中 $\log_{10}{n} \leq 6$ 。

2017 Multi-University Training Contest 1 solutions BY 北京航空航天大学》上有5条评论

  1. Pingback引用通告: HDU 6038 Function-Ocrosoft

  2. Pingback引用通告: HDU 6033 Add More Zero-Ocrosoft

  3. gunpowder

    各位老哥不要点开那个pingback引用公告的链接啊。。那是本蒟蒻自己的比赛总结,并非题解,毫无营养。因为在总结中有官方题解的链接,所以WordPress自动ping了这个页面才有了这个引用公告。。。丢人,丢人啊

  4. Pingback引用通告: 2017 Multi-University Training Contest 1 总结 | 火药

评论已关闭。