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,然后修改就完事了。

原文地址:https://www.cnblogs.com/zengzk/p/13888695.html