「学习笔记」FFT x 字符串匹配
设匹配函数 \(C(x,y)\) 为字符 \(x\) 和字符 \(y\) 匹配的值,是我们自己定义的值。
两个字符串匹配的值就是对应位置上的字符匹配的值的和。
对于文本串 \(S\) 和模式串 \(T\),现在要求出 \(T\) 在 \(S\) 中所有匹配的位置。
为了化成卷积的形式,把 \(T\) 反转。
这样 \(T\) 和 \(S\) 以 \(i\) 为结尾的子串的匹配值为:
为了能够区分不同位置的匹配值,定义生成函数:\(P(x)\),\([x^i]\) 代表 \(T\) 与 \(S\) 以 \(i\) 结尾的子串的匹配值。
那么:
为了能通过观察匹配值来确定两个字符串,构造匹配函数 \(C(x,y)=(x-y)^2\)(字符的权值需满足两两不同,可以使用 ASCII 码来作为权值),则两个字符串匹配当且仅当匹配值为 \(0\).
那么:
另外,为了使得边界满足卷积的形式,对于"溢出"的部分定义其权值为 \(0\),也就是我们需要计算:
前两个柿子可以预处理前缀和来做到线性求出,后面是个卷积的形式,可以通过 FFT \(\mathcal{O}(n\log n)\) 求出。
所以就可以 \(\mathcal{O}(n\log n)\) 做到字符串匹配了。
栗题一 luoguP4173
带通配符的字符串匹配。
尝试构造匹配函数 \(C(x,y)\) 满足:
-
\(x\) 或 \(y\) 为通配符时值为 \(0\);
-
\(x\) 和 \(y\) 都不为通配符,且相同时值为 \(0\);
-
\(x\) 和 \(y\) 都不为通配符,且不相同时值 \(>0\).
设通配符的权值为 \(0\),\(C(x,y)=(x-y)^2xy\).
(这里的次方是点乘,\(*\) 为卷积)
三次卷积,时间复杂度 \(\mathcal{O}(n\log n)\).
栗题二 Codeforces 528 D
分别仅考虑 \(A,C,G,T\),把匹配成功的位置取个交集就可以。
现在仅考虑 \(A\),把 \(S\) 中不会和 \(A\) 匹配上的位置上的字符设为 \(o\),把 \(T\) 中不是 \(A\) 的字符设为 \(\#\),则匹配函数 \(C(x,y)\) (其中 \(x\) 来自 \(S\),\(y\) 来自 \(T\))要满足:
- \(=0,x=A,y=A\);
- \(=0,x=A,y=\#\);
- \(>0,x=o,y=A\);
- \(=0,x=o,y=\#\).
这样的 \(C\) 才能满足匹配成功值为 \(0\),否则大于 \(0\).
设:
-
\(S\) 中的 \(A\) 值为 \(0\),\(o\) 值为 \(1\);
-
\(T\) 中的 \(A\) 值为 \(1\),\(\#\) 值为 \(0\);
-
\(C(x,y)=xy\).
对于每个字符只需要一次 FFT 就可以了。