2018-2019 ACM-ICPC, China Multi-Provincial Collegiate Programming Contest
Contest Info
[Practice Link](https://codeforces.com/gym/102222)
Solved | A | B | C | D | E | F | G | H | I | J | K | L | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
12/13 | O | O | O | O | Ø | O | O | O | Ø | Ø | O | Ø | - |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. Maximum Element In A Stack
题意:
维护一个栈,有\(POP\)和\(PUSH\)两种操作,每次操作完后输出栈中最大的元素是多少。
思路:
用栈维护一个二元组\((a, b)\),\(a\)表示当前的数值,\(b\)表示当前数字以及之前\(PUSH\)进来的数字中最大的是多少。
显然每次\(PUSH\)的时候可以通过转移得到当前的\(b\)。
那么每次答案就是栈顶的\(b\)
B. Rolling The Polygon
C. Caesar Cipherq
签到。
D. Take Your Seat
题意:
第一个问题:
有\(n\)个人坐飞机,他们的上机顺序是\(1 - n\),第一个人忘记了自己坐哪儿,其他人都知道自己的位置是哪里。
- 那么第一个人会随机选在一个位置坐下
- 其他人上机时,如果自己的位置没有被坐,那么它们会坐自己的位置,否则会随机选择一个空位坐下
- 询问最后一个上飞机的人坐在自己位置上的概率是多少
第二个问题:
- 在第一个问题的基础上,将上机顺序从\(1 - n\)改成随机
思路:
第一个问题:
在所有情况中,编号为\(n\)的人坐在自己位置上的情况数是一半,所以概率都是\(\frac{1}{2}\)。
第二个问题:
- 考虑只有当编号为\(1\)的人最后一个上飞机的时候,那么最后一个上飞机的人坐在自己位置上的概率是\(1\)
- 其他情况都是\(\frac{1}{2}\)(其实是第一种情况的扩展)
- 那么编号为\(1\)的人最后一个上飞机的方案数是\((n - 1)!\)
- 所以答案为:
E. 2-3-4 Tree
题意:
模拟2-3-4树。
- 2-3-4树是一棵搜索树,并且所有叶子结点的深度相同
- 按如下程序插入一个数字:
- 如果当前结点是一个4-node,那么将中间值删除,并且将移除中间值后的3-node分裂成两个2-node
- 如果当前结点是根节点,那么新建一个结点,值为中间值,两个儿子为分裂成的两个2-node,新建的结点为根,然后将当前结点置位根
- 否则将中间值合并给它的父亲,然后将当前结点置位其父亲
- 如果当前结点是一个叶子结点,直接插入
- 否则,按照搜索树的搜索流程找到一个叶子结点
思路:
模拟即可。
F. Moving On
题意:
给出\(n\)个点,每次询问\((u, v, w)\)表示\(u \rightarrow v\)中,经过的点的权值不超过\(w\)的最短路径是多少
思路:
考虑\(Floyd\)的\(DP\)过程\(f[k][i][j]\)表示经过前\(k\)个点的\(i \rightarrow j\)的最短路径是多少
那么将询问按\(w\)排序,并且将点也按\(w\)排序,然后每次询问前将还没有转移的小于当前询问的\(w\)的所有点进行转移
G. Factories
题意:
给出一棵树,选择\(k\)个叶子结点,使得\(k\)个叶子中任意两个点之间的距离之和最小
思路:
考虑\(f[u][i]\)表示\(u\)这个子树中选择了\(i\)个点的最小代价
那么枚举一个儿子\(v\)的转移如下:
记得转移的时候加入剪枝:
- 对于\(u\)来说,转移的\(i\)的上限是\(k\)和\(sze[u]\)取Min
- 对于\(v\)来说,如果某个状态是不合法的,那么后面的状态都不用转移
复杂度不清楚,但是不是\(O(nk^2)\)
H. Fight Against Monsters
题意:
有\(n\)个怪兽,每个怪兽有生命值\(a_i\)和攻击力\(b_i\),打每个怪兽是第\(i\)秒打\(i\)点伤害,所有怪兽从一开始就围攻你,每秒造成\(b_i\)点伤害,问你如果消灭这些怪兽使得你受到的伤害最少?
思路:
首先可以对每个怪兽算出\(t_i\),那么考虑两个怪兽\(i\)和\(j\),我们先打哪个,我们假设先打\(i\),那么受到的伤害是:
如果后打,那么受到的伤害是:
按\(pre < nx\)排序即可确定打怪顺序
J. Nested Triangles
题意:
给出两个点\(P\)和\(Q\),以及若干个点\(A_i\),要求选出尽量多的点\((v_1, v_2, \cdots)\),使得\(A_{v_i}\)内含于\(PQA_{v_{i - 1}}\)
如果有多种方案,输出字典序最小的
思路:
- 先将所有点按是在直线\(PQ\)的两侧分为两堆,然后分别考虑
- 考虑一个点\(i\)内含于三角形\(PQA_{v_j}\),那么有\(\angle_{PQA_{v_i}} < \angle_{PQA_{v_j}}\)以及\(\angle_{QPA_{v_i}} < \angle_{QPA_{v_j}}\)
- 但是不能直接存角度,这样可能会有精度问题,我们可以通过对\(P\)和\(Q\)的极角排序,对每个点进行离散化。
- 那么就转换成了一个二维偏序问题
- 字典序最小其实是个经典操作,按\(dp\)值分类,然后贪心取即可
K. Vertex Covers
L. Continuous Intervals
题意:
给出\(n\)个数,要求询问有多少个子区间满足:
\(Max\)表示区间最大值,\(Min\)表示区间最小值,\(DISTINCT\)表示区间不同数的个数
思路:
考虑用线段树维护这个式子,然后枚举右端点,考虑更新每个左端点的这个式子。
- 对于最大最小值的更新,可以维护两个单调栈
- 对于区间不同数的维护可以开个\(map\)记录一下上次出现的位置
- 然后注意到对于每个区间都有\(Max - Min - DISTINCT \geq 1\)
- 那么线段树维护一个区间最小值以及区间最小值的个数,如果区间最小值是\(-1\),那么这些个数就是有用的