ZLOJ练习40总结
written on 2022-07-13
写一点随记:
- 对于一张有向图,如何判环?
答:直接跑拓扑排序,将某一点加入队列的条件是这一点的入度为 \(0\),最后查看是否有点的入度不为 \(0\)。时间复杂度 \(O(n)\),代码实现也不难。
-
对于树上点权相乘有关的题目,可以考虑特殊情况,因为乘法的速度很快,可以考虑证明只有较小的某些值(如 \(1,2\))参与了乘法的累计。
-
\(\text{MLE}\) 的另一种可能原因是递归爆栈。
就这三点,然后具体看题目。
第三题太愚蠢,不写了。
第四题题目看错了,不写了。
第五题思路奇特,不写了。
好的先看第五题。
这题考场上的时间不是很够,匆匆敲了个骗分代码就交了。事实上这题的关键在于发现题目的数据范围。发现 \(n\leq 16\),那么很显然就有爆搜和状压两种思路。
但是没有很明显的思路,于是考虑先模拟一些情况。经过一些操作,我们发现:因为字符串顺序可更改,所以随便画一些点,就能够发现,对于几个字符串,它们构成的最小个数,也就是:
“对于每一个字母在每一个单词中出现的次数的 \(\min\) 加上 每一个字母在每一个单词中出现的次数减去这个 \(\min\)。”
有点绕,可以手动模拟感性理解一下。
然后给出一组样例:
4
abca
abc
ade
adf
然后根据这样的样例,就可以发现这样的思路是错的。
为什么呢?因为合并应当是有序的。也就是说这组样例中的 \(1,2\)/\(3,4\) 两串应当优先合并,因为他们的相同前缀更长。所以在状态转移时,就不是一个一个地加点,而是由子集转移而来!
至此我们已经有了基本的思路,现在的目标与思路就很明确了。原题即转化为将给定的字符串分成若干组,然后合并成新的组,最后求全集。接着就是转移的问题了,对于一个二进制状态,它的重组最长公共前缀是一定的,可以提前预处理好(代码中即为 \(sum\)),那么转移时,为了保证最优,肯定是用原先的两个答案相加,再减去这个前缀,答案可能偏大,因此转移时从每一个子集转移而来,这样就能够保证获得最优解。
代码在链接中。
第四题本来是一道很有价值的贪心转化题,但是题目看错了,导致前面的思考均为废谈,因此在这里就简单地说一下思路。
贪心的思路是很明确的,要考虑的问题就是对于环上的操作,贪心的正确性。一般来说,确定一个起点,在顺序扫描的时候顺便加入所有新的精灵值到 \(\texttt{multiset}\) 中,然后贪心的策略就很明显了。但是为了保证贪心的正确性,要是对于某一个矮人的分析中,选取的精灵是从后面的环绕回来的呢?那就有后效性了,因此本题的关键在于找到无后效性的起点。
就讲这么多,剩下的可以先自己思考一下,推出式子(这也不难),然后就可写了。
第三题可以参考一下其他的题解,剩下的就不再赘述了。