tmp
Posted kamimxr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tmp相关的知识,希望对你有一定的参考价值。
## T1
### $sub1$
没有问号的情况下,考虑如何线性判定。考虑每两位当作一组,对于每组有如下两种操作:
1. 将两位依次压入栈中;
2. 将第一位与栈中全部元素合并后,再将第二位压入栈中。
可以发现栈中的情况可以看作是关于下一个压入元素的函数,即 $G[a, b](x)$,表示当 $x = 0 $时返回 $a$,$x = 1$ 时返回 $b$。
假设当前栈中情况为 $G[a, b](x)$,考虑压入两位 $c, d$,容易根据上述两种操作合并出新的函数$G[a′ , b′ ](x)$。
由于本质不同的函数只有 $4$ 种,用 $f[i][j_0][j_1]$ 表示前 $i$ 位能否得到 $G[j_0, j_1](x)$。
### $sub2$
对于计数问题,$dp$ 套 $dp$ 即可,状态数是 $2^{4} n$。
## T2
显然答案是 $s$ 的子串,所以可以把 $s$ 的后缀自动机建出来,在上面考虑。
对于 `endpos` 集合相同的串,显然 `*` 的个数随着串的长度单调递增,所以可以二分这个长度 $len$,然后 `*` 的个数就是每相邻两个 `endpos` 的距离和 $len$ 取 $min$ 并求和。
这个东西也许可以线段树合并但没有必要,(大概)更好写的做法是在 fail 树上做树上启发式合并,并用 set 和树状数组维护相邻元素的距离。
最后为了比较哪一个串最优,再写个后缀数组即可。
## T3
首先,考虑到区间异或可以前缀和。我们把分割序列的断点取出来,那么就会得到一个分割方案的必要条件,即每个断点处的前缀和必须是给出的集合能够线性组合出来的数。
例如$ [1 , 1 , 4 , 5 , 1 , 4]$ 的前缀和为$ [1 , 0 , 4 , 1 , 0 , 4]$。则对于集合 $ { 1 , 4 }$ 和分割方案$ [1] , [1] , [4 , 5] , [1] , [4]$,则有前缀和 $1 , 0 , 1 , 0 , 4$。于是,能够马上得到一个结论:总是存在一种方案,使得最后构造出来的序列段数 $ m leq 2^ k$ 。
证明就是考虑到如果最终方案中有两个断点前缀和相同,例如 $[5 , 3 , 2 , 5]$,那么显然后三段的异或和为$ 0$,显然是可以和前面的 $5$ 并起来变成单个 $5$。从最简单的 $dp$ 开始考虑。 $f_ i$ 表示最后一个断点在 $i$ 是否可行。根据上面的结论,注意到如果有前缀和 $p_j = p_i ( j lt i )$,且有 $f _j = 1$,那么显然 $f_i $ 能贡献到的状态, $f_j$ 都能贡献到。
于是实际上我们只需要记录在所有的可行分割方案中,一个前缀和的出现位置的最小值 $f_ v$ ,如果不存在则设为 $n + 1$。容易证明最终的可行性就是 $f _{p _n} leq n$ 。一个值分别异或上查询集合里所有的数,可以得到这个数的转移目标的集合。
我们把序列前缀和的每种数单独提出来写成若干个位置集合,如果可以支持查询后继,就能转移:注意到对一个值 $v$ 如果有 $i < j $,且在 $ i $ 出查询过,如果没有后继,则在 $ j $处没有后继;如果有后继,显然 $ j$ 处的没有 $i$ 处的优。于是可以用类似最短路的写法,用一个优先队列 $bfs$,每种能线性组合出的数最多访问一次,所以单次询问最多调用 $O (k2 ^ k )$ 次查询后继操作。
剩下的问题是区间异或,查询一个值在序列中下一次出现位置。可以使用分块的技巧处理。对于每一块里,维护一个 $bitset$ 记录哪些数出现过,和一个异或标记。这样修改和询问的时候都暴力即可。
虽然复杂度 $O(nk2^ksqrt n)$ 有点爆炸,但出题人很菜,肯定卡不满,所以就可以跑过去了。
以上是关于tmp的主要内容,如果未能解决你的问题,请参考以下文章