01Trie
单发了,好厉害。
P7156 [USACO20DEC] Cowmistry P
先考虑 \(K\le10^6,m\le10^6\) 的部分分,也就是能够遍历 \(S\) 中的所有元素。
将它们塞进 01Trie 里。然后考虑直接 dp。
\(f_i\) 表示三个数都在节点 \(i\) 子树中的方案数,枚举它们分别在左 / 右子树,共有 [左3] [右3] [左2右1] [左1右2] 四种可能,其中前两种可以用 \(f\) 自身直接转移到,后两种需要再 dp 一次。具体转移大概需要关注 \(K\) 对应位是 \(0/1\) 就够了。
\(g_{i,j}\) 表示两个数在 \(i\) 子树中、一个在 \(j\) 子树中,枚举左右子树,共有 \(3\times2\) 种可能,同样是模拟,发现还需要增设一个 \(h_{i,j}\) 表示一个数在 \(i\) 子树中、一个在 \(j\) 子树中的方案数,这里分 \(2\times2\) 种情况,足够了。
分析复杂度,发现 \(g\) 只会由 \(f\) 调用,而这样的 \(g\) 只有 \(O(|S|)\) 个,同理 \(h\) 的调用数量也是 \(O(|S|)\) 的,因此虽然状态是二维,但是复杂度就是线性的。
正解需要一个厉害的 Trick:使用若干区间拆分掉大区间,具体来说小区间是 \([p2^k,(p+1)2^k)\) 的形式。
比如拆掉 \([0000,1011]\) 就是 \([0000,1000)\cup[1000,1010)\cup[1010,1011)\cup\{1011\}\)。
把这个过程画到 01Trie 上,发现每个区间都对应一棵满二叉树!显然在这题中,相同形态的子树的 dp 值都是相同的,于是直接用若干 "大点" 表示所有满二叉树,然后直接预处理 / 记忆化搜索出 "大点" 的 dp 值并统一放到一个满二叉树数组中。这样的话 01Trie 本身的复杂度仍然只和点数有关,这里一个大区间会被拆成 \(O(\log V)\) 个点,所以复杂度即为 1log。非常厉害。
具体可以看汤老师的题解。
代码就比较脑瘫了,谁爱写谁写吧 /qd