以第 i 个字符结尾的字符串中必定有一个 next[i] 的前缀,即 第 next[i] 的位置为 i 位置贡献 1,画出 next 图就是:
所以可以列出状态转移方程:
d
p
[
i
]
=
{
1
n
e
x
t
[
i
]
=
=
−
1
d
p
[
n
e
x
t
[
i
]
]
+
1
n
e
x
t
[
i
]
<
>
−
1
dp[i] = \begin{cases} 1 &&next[i] == -1\\ dp[ next[i] ] + 1 &&next[i] <> -1 \end{cases}
dp[i]={1dp[next[i]]+1next[i]==−1next[i]<>−1
如果存在,那么必定存在一个
k
(
2
∗
i
−
1
<
=
k
<
=
N
−
1
−
i
)
k( 2*i - 1<= k <= N-1-i )
k(2∗i−1<=k<=N−1−i),使得
S
[
k
−
i
+
1...
k
]
=
=
S
[
0...
i
−
1
]
S[k-i+1 ... k] = = S[0 ... i-1]
S[k−i+1...k]==S[0...i−1],所以必定有
N
e
x
t
[
N
e
x
t
[
.
.
.
[
k
]
]
]
=
=
i
−
1
Next[Next[...[k]]] = = i - 1
Next[Next[...[k]]]==i−1,所以我们可以预先将S[i … N-1-i]区间内所有的Next值退化后进行Hash,然后在枚举某个长度i的时候去Hash数组中找i是否被标记,如果被标记说明存在某个k满足
S
[
k
−
i
+
1...
k
]
=
=
S
[
0...
i
−
1
]
S[k-i+1 ... k] = = S[0 ... i-1]
S[k−i+1...k]==S[0...i−1],i 就是最大可能长度。
题意:给定 N * M (N <= 1000, M <= 1000) 的01矩阵S,再给定T(T <= 100) 个 P * Q (P <= 50, Q <= 50) 的01矩阵,问P*Q的矩阵中有多少个是S的子矩阵。
难度:★★★☆☆
题解:由于P <= 50,所以我们可以把所有 P * Q 的矩阵进行二进制位压缩,将 P * Q 的矩阵的每一列压缩成一个64位整数,这样 P * Q 的矩阵就变成了一个长度为Q的整数序列T,用同样的方式对 N * M 的矩阵进行压缩,总共可以产生 (N-P+1) 个长度为M的整数序列,剩下的就是进行最多 (N-P+1) 次KMP匹配了。
题意:给定一个长度为 N (N <= 105) 的字符串S,求在它的末尾添加几个字符使得他变成一个至少重复两次的连续重复串,要求添加的字符数最少。
难度:★★★☆☆
题解:将字符串当成是 X…XY 的形式来,其中 X 字符串的长度大于Y,Y 字符串的长度可能为 0;然后枚举的是 X 字符串的长度 XLen;
可以得到一些数据:
X
重
复
的
次
数
K
=
f
l
o
o
r
(
M
L
e
n
/
X
L
e
n
)
X重复的次数 K = floor(MLen / XLen)
X重复的次数K=floor(MLen/XLen)
Y
的
长
度
Y
L
e
n
=
M
L
e
n
−
X
L
e
n
∗
K
Y的长度YLen = MLen - XLen * K
Y的长度YLen=MLen−XLen∗K 然后根据叠串公式判断前缀
S
[
0...
X
L
e
n
∗
K
−
1
]
S[0 ... XLen * K-1]
S[0...XLen∗K−1] 是否是一个 X 的叠串;如果是,判断剩余的 Y 字符串是否为 X 的前缀,这一步可以通过预处理 next 数组来做;最后计算一个最小的 XLen - YLen 就是答案;