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)!\)
  • 所以答案为:

\[\begin{eqnarray*} \frac{(n - 1)!}{n!} + \frac{(n - 1)(n - 1)!}{2n!} = \frac{n + 1}{2n} \end{eqnarray*} \]

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\)的转移如下:

\[\begin{eqnarray*} f[u][i] = min(f[u][i], f[u][i - j] + f[v][j] + w * j * (k - j)) \end{eqnarray*} \]

记得转移的时候加入剪枝:

  • 对于\(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\),那么受到的伤害是:

\[\begin{eqnarray*} pre = b_it_i + b_j(t_i + t_j) \end{eqnarray*} \]

如果后打,那么受到的伤害是:

\[\begin{eqnarray*} nx = b_i(t_i + t_j) + b_jt_j \end{eqnarray*} \]

\(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\)个数,要求询问有多少个子区间满足:

\[\begin{eqnarray*} Max - Min + 1 = DISTINCT \end{eqnarray*} \]

\(Max\)表示区间最大值,\(Min\)表示区间最小值,\(DISTINCT\)表示区间不同数的个数

思路:
考虑用线段树维护这个式子,然后枚举右端点,考虑更新每个左端点的这个式子。

  • 对于最大最小值的更新,可以维护两个单调栈
  • 对于区间不同数的维护可以开个\(map\)记录一下上次出现的位置
  • 然后注意到对于每个区间都有\(Max - Min - DISTINCT \geq 1\)
  • 那么线段树维护一个区间最小值以及区间最小值的个数,如果区间最小值是\(-1\),那么这些个数就是有用的
posted @ 2019-08-16 21:41  Dup4  阅读(811)  评论(0编辑  收藏  举报