原题不卡常,但是被某个出题人搬到校内 OJ 上开了 2s 1024MB,怎么回事呢?
首先我们可以把回文改写成 \(x\operatorname{xor} x^R=0\),这样只需要维护 \(x\) 的下 \(\frac{m}{2}\) 位即可。
考虑一个常见的套路,将 \([l,r]\) 拆成 \(O(\log V)\) 个区间,这些区间满足前若干位是定的,后若干位可以任选。
则可以设出一个 dp 状态:设 \(dp_{i,j,S}\) 表示考虑前 \(i\) 个数,后 \(j\) 位是任选的,前 \(S\) 位是定的,转移平凡。这样直接转移看上去复杂度是 \(O(\log^n V)\) 的,大概可以过 \(n\leq 4\)(
但是实际上,我们可以说明,\((j,S)\) 二元组的取值只有 \(O(m2^n)\) 个。考虑我们给一个已有的状态集合转移一个 \([L,R]\),对于一个最终状态,其 \(j\) 会取最大值,分类讨论:
- 若其最大值在 \([L,R]\) 取到,则其 \(j\) 位之前只有 \(2\) 种情况。
- 若其最大值在原状态取到,则其异或的 \([L,R]\) 只有 \(2\) 种情况。
综上,每次转移只会增加 \(O(1)\) 个状态,可以进一步证明其只有 \(2^n\) 种,不想写了(
所以暴力建立 01Trie 转移能过 \(n\leq 18\) 或者 \(m\leq 30\),能过很多分!
然后发现 \(2^{\frac{n}{2}}\) 是可以接受的,于是直接 meet in middle 就行了!
吗?
发现好像是不太行的,因为转移是 \(O(m)\) 的,状态是 \(O(m\times 2^{\frac{n}{2}})\) 的,寄了。
考虑优化转移,转移的瓶颈在于取 \(\max\),转移式子中有 \(\max\) 前缀和一下,转移完再差分回去就行。
这样转移只需要转移 Trie 同一层的节点,复杂度是 \(O(m2^{\frac{n}{2}})\) 的。
这样就能过原题数据了,但是不太能过校内 OJ。
一点技巧:
- 不需要记录前缀和之后差分出来的值,因为没啥用。
- 垃圾回收可以少 \(\frac{1}{2}\) 内存。
- 开
unsigned int
instead oflong long
。
大概能过,目前应该是 LOJ 最优解 submission