「CTS2019 | CTSC2019」重复(Kmp)
「CTS2019 | CTSC2019」重复(Kmp)
Part1
首先我们考虑对于一个已经确定的 \(t\) 串,如何检查是否合法
对于 \(s\) 串建立 \(\text{kmp}\) ( \(\text{kmp}\) 自动机当然可以),
如果当前 \(\text{kmp}\) 指针 \(j\) 在 \(\text{fail}\) 树上的祖先所对应的所有下一个位置 \(s[ancestor+1]\) 中,存在一个字符, \(t\) 中当前位置的字符 \(t[i]<s[ancestor+1]\)
那么就是存在一个"有意义的串",并且这个串和s串第一个不同的位置就是 \(ancestor+1\)
所以可以预处理一个 \(fail\) 树上祖先最大的 \(s[ancestor+1],Max[state]\)
1 | rep(i,1,n) Max[i-1]=s[i]; |
配合dfs枚举,可以拿到pts10
Part2
设状态转移为 \(Trans[state][c]\)
把kmp状态压进dp状态里
如果把问题直接放到无穷意义下来看
那么跑够长度之后,后面的任意加入 \(m\) 次字符都会构成一个循环
枚举循环开始状态为 \(st\) , \(\text{dp}\) 走了 \(m\) 步回到 \(st\) 的方案数
如果计算合法方案数,那么还要多一维,所以直接计算不合法方案,也就是
\(Trans[state][Max[state]..25]\) 这一段转移是不会出现合法情况的
最后减一下
复杂度 \(O(m\cdot n^2)\)
1 | namespace pt2{ |
Part3
观察上面一档情况,合法的转移 \(Trans[state][Max[state]..25]\)
如果枚举下一个字符 \(c>Max[state]\) ,那么在 \(s\) 串中就找不到任何匹配了,下一个状态就是 \(0\)
否则,下一个状态就是 \(Trans[state][c]\)
也就是说,每个点出发其实只有两种情况,一种是一定会经过 \(0\) 的
所以对于这个环是否经过 \(0\) 进行讨论
如果不经过 \(0\) ,那么考虑直接从 \(st\) 出发走 \(m\) 步非0转移即可
经过 \(0\) 的,预处理一个从 \(0\) 出发,走了 \(i\) 步第一次回到 \(0\) 的方案数
\([st\rightarrow 0,0\rightarrow 0,0\rightarrow 0...,0\rightarrow st]\)
长成这个样子的转移
枚举第一个 \(st\rightarrow 0\) 的时间,后面可以预处理出来
复杂度 \(O(n\cdot m)\)
1 |
|