Educational Codeforces Round 97 (Rated for Div. 2)/Codeforces1437 ABCDEG
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\)分钟操作。
然后转移方程是
最后的答案是
其中,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,然后修改就完事了。