-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
790 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
\section{常系数齐次线性递推} | ||
\index{L!Linear Difference Equation} | ||
给定系数$a_0,a_2,\cdots,a_k$,有一个信号${f_n}$,满足$k$阶齐次线性差分方程 | ||
$\displaystyle \sum_{i=0}^k{a_if_{n-i}}=0$对所有$n$成立。现在给定信号 | ||
${f_n}$中的连续$k$项,求信号的任意一项。 | ||
|
||
一般$a_0$取1,其余系数取反,那么有$\displaystyle f_n=\sum_{i=1}^k{a_if_{n-i}}$, | ||
假设给定了$f_0,f_1,\cdots,f_{k-1}$的值,现在要求出$f_n$的值。 | ||
|
||
如果$k$足够小,那么很容易构造转移矩阵,记向量$F_i$表示$(f_{i+k-1},f_{i+k-2},\cdots,f_i)$, | ||
很容易构造$k*k$的转移矩阵$A$,其中$i$向$i+1$转移系数为1,$i$向$1$转移系数为$a_i$。即 | ||
$A[i+1][i]=1,A[1][i]=a_i$,那么有$F_n=A^nF_0$。使用矩阵快速幂可得到 | ||
$O(k^3\lg n)$的算法。 | ||
|
||
注意原等式左右向量取第$k$项仍然成立,即$(F_n)_{[k]}=(A^nF_0)_{[k]}$。左边就是$f_n$, | ||
右边就是以$A^n$的第$k$行为系数的$f_{0,\cdots,k-1}$的线性组合。记这些系数为 | ||
$c_{0,\cdots,k-1}$,同样将$f_{0,\cdots,k-1}$表示为$A^nF_0$的形式,有 | ||
$A^n=\displaystyle \sum_{i=0}^{k-1}{c_iA^i}$,记右式为矩阵$A$的多项式表达$R(M)$。 | ||
设存在矩阵多项式$F(M),G(M)$,满足$G(M)$的次数为$k$,$F(M)G(M)$的次数为$n$, | ||
且$M^n=F(M)G(M)+R(M)$。根据Cayley-Hamilton定理,若$G(M)$为矩阵$A$的特征多项式, | ||
其次数恰好为$k$且$G(A)=0$。由于$G(M)$的次数为$k$,$R(M)\equiv M^n\pmod{G(M)}$, | ||
多项式取模可求出$R(M)$。并且由于$G(A)=0$,此时有$A^n=R(A)$。拿到$R(M)$后就可以直接$O(k)$ | ||
求值。 | ||
|
||
接下来讨论如何构造出矩阵$A$的特征多项式$G(M)$。根据定义有 | ||
$G(\lambda)=\textrm{det}(\lambda I_k-A)$,多项式高斯消元求行列式十分麻烦。 | ||
注意到矩阵$\lambda I_k-A$的特殊性,将第一行每一项的代数余子式求和,去除第一行第$i$ | ||
列后都会得到一个下三角矩阵,行列式值为对角线上元素之积,同时代数余子式的$(-1)^{i+1}$项 | ||
与子矩阵的$-1$项恰好抵消。综上所述,$G(\lambda)=\lambda^k-a_1\lambda^{k-1}-\cdots-a_k$。 | ||
|
||
因此该方法的性能瓶颈在多项式取模上,时间复杂度$O(k\lg k\lg n)$。引入$\lg n$的原因是 | ||
我们无法直接构造一个多项式$x^n$然后以$n$的规模做取模,由于该多项式较为简单,可以使用类似 | ||
模意义快速幂的方法做模$R(M)$意义下的多项式快速幂。 | ||
|
||
好写的优化技巧: | ||
\begin{itemize} | ||
\item 预处理出$G(x)$与$G_{rev}^{-1}(x)$的点值表达。 | ||
\item 需要取模时才实例化取模。 | ||
\end{itemize} | ||
|
||
参考代码: | ||
\lstinputlisting{Source/Templates/LR.cpp} | ||
|
||
上述内容参考了《线性代数及其应用》\cite{LAIA5}4.8节以及shadowice1984的博客 | ||
\footnote{ | ||
题解 P4723 【【模板】线性递推】 | ||
\url{https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p4723} | ||
}。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
\section{卷积法解决字符串匹配问题} | ||
\subsection{回文子序列} | ||
以某个位置为对称轴的回文子序列的个数可以由关于这个位置对称的字符对数计算。 | ||
每一对都有选与不选两种选择,除去全不选的情况,记对称字符对数为$k$,方案为$2^k-1$。 | ||
|
||
接下来考虑如何计算出对称字符对数。若字符串按照Manacher算法处理,对于每个对称中心$i$, | ||
以它为对称中心的字符对满足$S[i-x]=S[i+x]$,注意到$i-x+i+x=2i$为定值,可以联系到卷积。 | ||
枚举字符集的字符,将有该字符的位置标为1,其余标为0,做一遍自卷积,位置$2i$的系数指示了以 | ||
$i$为对称中心的当前字符对数。由于同一个位置上会被统计1次,不同位置的对会被统计2次,所以 | ||
(系数+1)/2才是实际对数。时间复杂度$O(|\Sigma|n\lg n)$。 | ||
|
||
事实上卷积时不一定用Manacher算法预处理,将偶回文序列的对称轴看做$x.5$,其两倍仍然是 | ||
整数,可直接统计$[1,2n]$全部系数。 | ||
|
||
\subsubsection{例题} BZOJ3160: 万径人踪灭 | ||
|
||
本题要求的是回文子序列数,去掉是连续一段的回文子串。回文子序列数可以使用FFT卷积或者 | ||
序列自动机实现,回文子串数可以用Manacher或者PAM实现。 | ||
|
||
参考代码(NTT+Manacher): | ||
\lstinputlisting{Source/Source/'FFT NTT'/BZOJ3160.cpp} | ||
|
||
由于卷积出的值很小(在$n$的范围内),FFT、NTT均可,注意控制FFT的精度(做完除法操作后 | ||
使用固定eps,如果想要省去除法操作,需要将eps乘以FFT规模作为实际eps)。 | ||
\subsection{带通配符匹配} | ||
给定母串$S$与带通配符的模板串$P$,求$P$在$S$中的出现位置。 | ||
|
||
首先考虑不带通配符匹配的问题,可以使用KMP解决(带通配符则无法保持nxt的性质),但也有卷积 | ||
的方法。考虑如何将其表示为卷积的形式。如果母串$S$在位置$i$处匹配了$P$,那么有 | ||
$S[i+k-1]=P[k],1\leq k \leq|P|$。等式两边的下标之和不为定值,但它们的差为定值。那么 | ||
可以将$P$取反为$P_{rev}$,有$S[i+k-1]=P_{rev}[|P|-k+1],1\leq k \leq |P|$,两边 | ||
下标之和为$i+|P|$,可以进行卷积。同样考虑枚举字符集的字符,将有该字符的位置置为1,其余置0。 | ||
将每次卷积的结果累加,若位置$i+|P|$上的系数为$|P|$,则说明母串$S$在位置$i$匹配上了$P$。 | ||
|
||
有通配符的情况类似,每个有通配符的位置强制置1。 | ||
|
||
这种方法的时间复杂度仍为$O(|\Sigma|n\lg n)$。 | ||
\subsection{大字符集处理} | ||
对于$|\Sigma|$较大的情况(比如26个字母),26次DFT的时间无法被接受。考虑如何把它们 | ||
放在一个式子内计算。考虑不带通配符的情况,将字母表示为数字,对应位相等则数字差为0。用 | ||
区间内差的绝对值之和为0表示整段对应区间数字差为0比较麻烦,索性使用平方和。那么有 | ||
$V[x]=\displaystyle \sum_{i=1}^{|P|}{(S[x+i-1]-P[i])^2}=0$,将平方展开,$P$ | ||
取反得到 | ||
\begin{displaymath} | ||
V[x]=\displaystyle \sum_{i=1}^{|P|}{S[x+i-1]^2+P_{rev}[|P|-i+1]^2-2S[x+i-1]P_{rev}[|P|-i+1]} | ||
\end{displaymath} | ||
仅需做一次卷积。考虑带通配符的情况,通配符无法表示为与26个数字都相等的数字,但是可以令其为0, | ||
作为平方和的系数,也可以使整个式子的值为0。将式子拆开后可表示为两个卷积+一个常数的形式。 | ||
如果母串也带通配符,则再乘一个系数,表示为三个卷积之和。 | ||
|
||
参考代码: | ||
\lstinputlisting{Source/Source/'FFT NTT'/BZOJ4503.cpp} | ||
|
||
{\bfseries 使用FFT时,若最后不做除法,eps要开大些,比如0.5*p。 | ||
可以在做点值乘法时直接求和,仅需一次IDFT。} | ||
|
||
上述内容参考了小蒟蒻yyb的博客\footnote{ | ||
[复习]多项式和生成函数相关内容 | ||
\url{https://www.cnblogs.com/cjyyb/p/10132855.html} | ||
}。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,4 @@ \chapter{字符串} | |
\input{String/SAM} | ||
\input{String/Parser} | ||
\input{String/ZAlgorithm} | ||
\input{String/Convolution} |
Oops, something went wrong.