【题解】「CQOI2014」通配符匹配

【题解】「CQOI2014」通配符匹配

https://www.luogu.com.cn/problem/P3167


\(s\) 为模式串,\(t\) 为文本串。

首先有一个显然的的 dp 是,\(f_{i,j}\) 表示模式串的前 \(i\) 个和文本串的前 \(j\) 个是否匹配。

显然 \(O(n^2)\) 是过不了的。

Motivation: 注意到题目限定了通配符不多于 \(10\) 个,而在模式串里面如果不包含通配符其实是可以打包处理的。

所以我们考虑修改 dp 的定义为 \(f_{i,j}\) 表示模式串的前 \(i\)通配符 和文本串的前 \(j\) 个字符是否匹配。

这样的话,转移就变成了:设当前这一段的长度为 \(l\),通配符为 \(c\),下标为 \(p\)

\[f_{i,j}=\begin{cases} f_{i-1,j-l} & \text{ if } c=\mathsf{?}\wedge s[p-l+1\cdots p-1]=t[j-l+1\cdots j-1] \\ f_{i-1,k}(0\le k\le j-l+1) & \text{ if } c=\mathsf{*}\wedge s[p-l+1\cdots p-1]=t[k+1\cdots k+l-1] \\ \end{cases} \]

但是现在发现一个新问题,第二种转移需要枚举前缀,这会使我们的算法退化到 \(O(n^2)\)

我们不考虑填表法,而考虑刷表法。

前者是根据根据一定限制条件来找可能造成贡献的 dp 值,而后者是找出可以对那些 dp 值造成贡献。

(但是两种各有所长,一般二者皆可,但是某些题目里面只能用其中的一种。

考虑刷表法。转移改写成:

\[f_{i,j}\to\begin{cases} f_{i+1,j+l} & \text{ if } c=\mathsf{?}\wedge s[p-l+1\cdots p-1]=t[j+1\cdots j+l-1] \\ f_{i-1,k}(j+l-1\le k\le |t|) & \text{ if } c=\mathsf{*}\wedge s[p-l+1\cdots p-1]=t[j+1\cdots j+l-1] \\ \end{cases} \]

我们注意到,现在第二种转移虽然还是要枚举 \(k\),但是每次需要判断是否匹配的子串是相同的,所以我们可以直接打个标记,最后统一更新后缀就好了。

posted @ 2024-08-27 21:09  CloudWings  阅读(8)  评论(0编辑  收藏  举报