20260813 - 字典树

今天居然没有罚时诶,两个 CE 居然不算!

写 Trie 时应该思考什么

  1. Trie 中的一个节点代表什么?
    • 每一个节点的下一个节点,是否是结尾
  2. 从根到一个节点的路径代表什么?
    • 存入字符串的前缀。
  3. 一个节点的子树代表哪个字符串集合?
    • 代表以根到该节点的路径所代表的前缀为前缀的字符串集合。
  4. cnt[u] 和 ed[u] 有什么区别?
    • 前面的是经过点的个数,后面的结尾的个数。
  5. 为什么把整数写成二进制后,也可以建立 Trie?
    • 因为写成 \(0/1\) 后可以更好地处理二进制问题。
  6. 什么题适合 Trie,什么题不适合?
    • 一般前缀相关的问题都可以通过 Trie 来解决,非前缀比如字符串匹配等问题就不能使用。

令人欣慰的是,今天的字典树代码强度直线下降。

顺带一提,trie 在英式英语中读作 /triː/,在美式英语中读作 /traɪ/,所以 mmt 说的 try 也是有道理的。

A - trie模板

事实证明,封装的 trie 也是有好处的,这样不用每次维护了。

枚举每篇短文,将其所有单词丢进 Trie 里边,然后直接找就行了。

B - Karuta

显然,每个点最大的 LCP 就是离他最近的分叉口,可以用树形 DP 维护。

分叉维护可以在字典树上维护。

C - Secret Message G

观察到,前缀长度等于字符串中较短的长度,分两种情况:如果消息长度比暗号要短,那么去把前缀的 end 数组累加起来;如果消息长度比暗号要长,那么暗去把结尾的 count 数组加进去。

D - Yet Another Sigma Problem

由于子树子串的个数就是在 LCA 位置的个数,所以每次插入的时候直接加上个数。

E - 01trie模板

我们发现异或两次等于没有异或,所以可以考虑每个点到根的异或和。

如果最高位还更大,那么其他位置再大也没有用。

所以贪心的查找,另一边有就往另一边找,没有只好走下去。

F - Perfect Security

由于前面的字典序都小了,那么后面的再大也赶不上。

所以考虑贪心,把 P 数组加入 Trie,每次查找完就删掉。

G - Forbidden Prefix

方法一:其实如果有了一个前缀 \(X\) 插入到了字典树里面,那么字数内所有的 \(Y\) 都挂了。

所以直接打上标记,下次不在访问即可。

方法二:同样的,如果访问到了一个 \(X\),就打上标记,然后字数内就不访问了。

类似线段树,每次类似 pushup 的时候可以合并每个子树的信息,如果有标记就清空。

H - Edit to Match

注意到,插入后直接判断是长度还是剩下的乘二更小就好了。

I - Dr. Evil Underscores

具体来说,如果全部都在左边,就递归左子树。

如果都在右边,就递归右子树。

如果两边看起来都可以,就分别递归。

诶,时间复杂度不会爆炸吗?

因为深度最大 \(\log n\) 层,所以复杂度不会爆。

J - A Lot of Games

分三种情况讨论

  1. 后手能必胜,那么后手如果一直赢就赢了。
  2. 先手能必胜,且可以必输,那么先手如果一直输到最后一次赢就可以了。
  3. 先手必胜但不能保证必输,那么每次都赢然后交换位置。\(k\) 为奇数时先手赢,反之后手赢。
posted @ 2026-08-13 21:26  AKCoder  阅读(12)  评论(0)    收藏  举报