Educational Codeforces Round 97 (Rated for Div. 2)/Codeforces1437 ABCDEG

AC代码

A. Marketing Scheme

如果\(2 \cdot l \le r\)就可以,反之不行。

B. Reverse Binary Strings

易得:最后要么是010101...要么是101010...

分别枚举两种情况,算出每种情况下需要翻转的位置,记\(r_i\)为第\(i\)位是否需要翻转,\(r\)中极大全1子段的个数即为答案。

C. Chef Monocarp

看到\(n\)的取值范围就觉得不对劲,想了想直接\(O(n^3)\)DP莽了。

首先猜结论:\(t_i\)小的盘子必定先操作。所以先给\(t\)排个序,方便之后DP。

\(dp_{i, j}\)表示考虑前\(i\)个盘子,第\(i\)个盘子在第\(j\)分钟操作。

然后转移方程是

\[dp_{i, j} = |j - t_i| + \min_{k = 0}^{j - 1} dp_{i - 1, k} \]

最后的答案是

\[\min_{i = 1}^{400} dp_{n, i} \]

其中,400是时间的上界。

D. Minimal Height Tree

易得:如果\(a_i < a_{i + 1}\),那么\(a_i\)可以和\(a_{i + 1}\)共享同一个父亲。反之,不行。

根据观察,就可以通过一个BFS的过程去构造出答案。

首先,在队列中加入\((1, 0)\)。二元组第一个元素表示节点上的值,第二个元素表示节点所在深度。

然后从\(2\)\(n\)依次处理元素:

  • 每次拿出队首,如果队首没有子节点或者说子节点的最大值小于当前元素,那么当前元素就可以作为队首的子节点,深度位队首的深度加一。所以将\((a_j, depth + 1)\)入队。
  • 否则,说明队首无法再接受任何子节点,就将队首出队,然后再走到第一步。

这样通过BFS保证了构造出来的树的BFS序满足条件,并且尽可能地利用了已有的节点,有点贪心的意思吧。

E. Make It Increasing

这题其实挺显而易见的吧,一眼看出了做法,就是根据\(b\)中的元素将序列划分为多段,每段去做一个LIS,就是LIS要加限制条件而已。

然后调了一个多小时都没调出来。赛后看了jiangly大佬的代码,发现他让\(a_i = a_i - i\),代码编写难度直线下降。

具体讲一下吧,就是先让\(a_i = a_i - i\)。然后如果存在\(a_{b_i} > a_{b_{i + 1}}\),则无解。

然后我因为不想讨论边界,所以在两端假了哨兵节点。

现在就是根据\(b\)中的元素将\(a\)划分为多段,每一段可以单独求解出最小的代价,所有段最小代价的和就是总的最小代价。然后每一段的最小代价和就是\(段长度-段带限制LIS长度\),带限制就是LIS中的元素的值必须大于左端点,小于右端点。

jiangly的做法很大的减少了代码复杂度,因为如果不这样处理的话,在做带限制LIS时,为了判断是否满足限制还要判断下标的关系。而做了处理之后,如果大于就说明了满足限制,所以就容易写了很多。

G. Death DBMS

卡E,最后几分钟才看到这题,AC自动机板子,不过好久没写了大概率调不出来。

大概就是前\(n\)个人名算模式串,后面查询最大值的算文本串,然后就是多模式串匹配,然后就能想到AC自动机。存值就是每个节点开一个multiset,保存在当前节点结束的模式串的权值。

先将模式串都加入AC自动机,之后查询的时候就是把文本串拿到AC自动机里跑,失配的时候就暴力跳fail链,然后查询就是查询fail树上根到当前路径的最大值。然后询问路径最大值的时候跳fail链会TLE,所以想到了类似虚树的优化。就是在建fail树的时候要计算出每个节点上一个有效点的位置在那里,记为last。跳last链就不会TLE,复杂度好像可以证明是\(O(n \sqrt n)\)的。

更新点权就是插入的时候记录对应串截至在那里,然后根据节点id找到对应的multiset,然后修改就完事了。

posted @ 2020-10-28 01:03  _Backl1ght  阅读(115)  评论(0编辑  收藏  举报