2019 Multi-University Training Contest 6
Contest Info
[Practice Link](https://cn.vjudge.net/contest/313507#overview)
Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
8/12 | - | O | - | Ø | O | O | - | O | Ø | Ø | - | O |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
B. Nonsense Time
题意:
给出一个排列\(p_i\),第\(i\)时刻第\(k_i\)个数会被解封,问每个时刻解封的序列中的最长上升子序列的长度。
保证\(p_i\)和\(k_i\)随机生成。
思路:
随机的排列中的最长上升子序列的长度的期望为\(\mathcal{O}(\sqrt{n})\)。
那么我们考虑\(f[i][j]\)表示以\(j\)结尾的长度为\(i\)的最长上升子序列最迟在什么时候出现。
那么转移的时候直接去找小于在自己之前,数字小于自己的,出现的最早的长度为\(i - 1\)一个位置,然后更新本轮的时间。
如果某一轮每个位置都没有长度为\(i\)的,那么就可以直接退出了。
时间复杂度\(\mathcal{O}(n\sqrt{n}logn)\)
D - Speed Dog
题意:
有\(A、B\)两个人做题,做第\(i\)道题,\(A\)需要敲\(a_i\)的代码,\(B\)需要敲\(b_i\)的代码,但是他们可以分工,也就是说对于每道题,它们可以选择一个\(x_i\),使得\(A\)敲\(x_ia_i\)的代码,\(B\)敲\((1 - x_i)b_i\)的代码.
现在给定\(n\)道题,对于每前\(i\)道题目,假设\(A\)敲的代码总量为\(C_a\),\(B\)敲的代码总量为\(C_b\),现在要最小化\(max(C_a, C_b)\)。
思路:
- 考虑最优解的情况下一定是\(C_a, C_b\)。
- (再猜测肯定有部分\(x_i\)全取\(1\),有一部分\(x_i\)全取\(0\),那可以按\(\frac{a_i}{b_i}\)排序,左边的\(x_i\)全取\(0\),右边的全取\(1\)。
- 每次二分中间那个\(x_i\)的位置,然后计算一下即可。
E. Snowy Smile
题意:
有\(n\)个宝藏,每个宝藏有权值\(w_i\),现在要求选择一个矩形,矩形内的所有的宝藏的权值和即为分数,问能够获得的最大分数是多少?
思路:
考虑\(n^2\)枚举上下边界,然后线段树维护区间最大子段和。
H. TDL
题意:
定义\(f(n, m)\)为\(> n\)的第\(m\)个与\(n\)互质的数,现在要知道一个最小的\(n\),使得下式成立:
思路:
考虑\(gcd(n, x) = gcd(n, x - n)\)。
那么\(f(n, m) - n\)其实就是第\(m\)个与\(n\)互质的数,考虑质数的密度很高,那么\(f(n, m) - n\)的范围不会很大。
直接暴力枚举。
I. Three Investigators
题意:
给出\(n\)个数,要求找出不超过\(5\)个最长上升子序列,使得选出的子序列的和最大。
思路:
考虑杨表求解\(LIS\)的过程:
- 从\(1\)到\(n\)依次考虑序列中的每一个数,将其插入到杨表的第一层
- 插入\(x\)的时候,如果\(x\)不小于这一层的最大的数,则将\(x\)放到这一层的末尾;否则找到大于\(x\)的最小的数\(y\),将\(y\)替换为\(x\)时,将\(y\)插入到下一层。
- 每一层的元素有序,寻找\(y\)可以二分查找
对于本题来说,我们要求的是序列和,那么我们将\(a_i\)拆成\(a_i\)个\(a_i\),那么问题转化为:找出\(5\)个不相交的不下降的子序列,使得这些子序列包含的元素个数最多。
那么就是杨表前五层的长度之和。
但是我们不能暴力插入\(a_i\)个\(a_i\),但是我们可以将杨表中相同的元素合并,用\(map\)记录,每次先消费后继,然后减少后继个数,并将其插入到下一层。
但是需要到某一类数字被消费完毕后,要及时从\(map\)中删除,否则二分的时候会有问题。
注意到每一次插入最多导致一种其他数字被拆分,那么每一层的插入次数最多为上一层的两倍。
那么前\(k\)层的杨表求解的复杂度为\(O(2^knlogn)\)
J.Ridiculous Netizens
题意:
有一棵树,现在询问有多少个子树中所有点的权值之积小于等于\(m\)。
\(n \leq 2000\)
思路:
- 考虑枚举一个根,计算子树中包含根的方案数是多少。
- 令\(f[u][S]\)表示当前点为\(u\),并且包含了根,并且\(\left\lfloor \frac{m}{S} \right\rfloor\)为\(S\)的方案数。\(val\)表示子树点权乘积。
- 用\(\left\lfloor \frac{m}{S} \right\rfloor\)表示乘积而不是直接用\(S\)是因为\(\left\lfloor \frac{m}{S} \right\rfloor\)的取值只有\(2\sqrt{n}\)种,并且\(\left\lfloor \frac{m}{ab} \right\rfloor = \left\lfloor \frac{\left\lfloor \frac{m}{a} \right\rfloor}{b} \right\rfloor\),保证了转移的正确性。
- 首先将自己已有的方案,强制选儿子,将方案数转移给儿子,等儿子做完它子树里的转移后,再累加它的贡献。因为此时儿子的方案数表示的是强制选了儿子及其祖先的满足条件的方案数
- 然后通过点分治枚举根即可。
L. Stay Real
题意:
有一个小根堆,\(A、B\)两个人轮流选取一个叶子结点,将其权值加到自己分数中。
两个人都尽量想让自己的分数高,问最终两个人的分数是怎样的。
思路:
考虑如果在一个序列在任意取数,那么肯定是排序之后,\(A\)取最大的,\(B\)取次大的,这样轮流取下去。
而小根堆的限制刚好就是这样。
每次可以取的数中一定有剩下的数中最大的,那么直接取即可。