利用到了
k
m
p
kmp
kmp和
m
a
n
a
c
h
e
r
manacher
manacher的部分思想。
个人理解只能称的上是部分。
扩展kmp处理的是:对于一个串
T
T
T,串
S
S
S每个后缀和串
T
T
T的最长公共前缀。
对于一个串
S
[
1...10
]
,
T
[
1...100
]
S[1...10],T[1...100]
S[1...10],T[1...100]。
如果已经匹配到了
S
[
1...10
]
=
T
[
1...10
]
S[1...10]=T[1...10]
S[1...10]=T[1...10].
且
S
[
1...5
]
=
S
[
2...6
]
S[1...5]=S[2...6]
S[1...5]=S[2...6]。
[以上为条件]
容易得到:
S
[
2..6
]
=
S
[
1...5
]
=
T
[
1...10
]
S[2..6]=S[1...5]=T[1...10]
S[2..6]=S[1...5]=T[1...10]。这正是利用到了
k
m
p
kmp
kmp的思想。我们得到了这部分处理过后的信息,然后继续处理。(暴力判断)
但是
k
m
p
kmp
kmp中预处理的
n
e
x
t
next
next数组表示的意思是最长相同前缀后缀。而这里的
n
e
x
t
next
next数组表示的是最长相同前缀[具体是串
S
S
S第
i
i
i个点开始的后缀和
S
S
S的最长公共前缀。]
显然这一部分信息等价于题目要求最长公共前缀。
那么怎么求解呢?
首先假设我们已经处理出了
1
k
1~k
1 k的情况,并且之前匹配过的最远位置是
p
p
p,
p
=
m
a
x
(
i
+
e
x
t
e
n
d
[
i
]
−
1
)
p=max(i+extend[i]-1)
p=max(i+extend[i]−1)设取最大值的位置是
p
0
p0
p0
这里是盗用了洛谷题解里的图片。
我们在处理
k
+
1
k+1
k+1的时候,
k
+
1
+
n
e
x
t
[
k
+
1
]
−
1
<
k+1+next[k+1]-1<
k+1+next[k+1]−1<和
>
=
p
>=p
>=p我们分两种情况.
首先设
L
=
n
e
x
t
[
k
+
1
]
L=next[k+1]
L=next[k+1]。
-
L
+
K
<
P
L+K<P
L+K<P
S [ k + 1... k + L ] = T [ b . . . b + L − 1 ] 。 S[k+1...k+L]=T[b...b+L-1]。 S[k+1...k+L]=T[b...b+L−1]。这一部分由于在p以内,显然是匹配过的。
T [ b . . . b + L − 1 ] = T [ 1... L ] = S [ k + 1... k + L ] 。 T[b...b+L-1]=T[1...L]=S[k+1...k+L]。 T[b...b+L−1]=T[1...L]=S[k+1...k+L]。
同时 T [ b + L ] ! = T [ L + 1 ] , T[b+L]!=T[L+1], T[b+L]!=T[L+1],因为这是计算过的最大前缀,必然后面不相等.
T [ 1 + L ] ! = T [ L + b ] = S [ k + L + 1 ] T[1+L]!=T[L+b]=S[k+L+1] T[1+L]!=T[L+b]=S[k+L+1]。因为 L + K < P , L+K<P, L+K<P,这部分信息已经匹配过相等,但是又有前面不相等,所以。 T [ 1 + L ] ! = S [ k + L + 1 ] . T[1+L]!=S[k+L+1]. T[1+L]!=S[k+L+1].
L L L 是 S [ k + 1 ] S[k+1] S[k+1]和 T T T最大公共前缀。 - L+K≥P
此时情况比较复杂。
我们能够确定的是: S [ k + 1... P ] = T [ b . . . P − P 0 + 1 ] = T [ 1.. p − k ] S[k+1...P]=T[b...P-P0+1]=T[1..p-k] S[k+1...P]=T[b...P−P0+1]=T[1..p−k]这部分是相等的。
剩下的就暴力匹配即可。
从 T [ p − k + 1 ] 和 S [ p + 1 ] T[p-k+1]和S[p+1] T[p−k+1]和S[p+1]开始。
求 n e x t next next的时候等价于上面,唯一需要注意的是第一位必定是 l e n len len,所以第一位不要考虑。特判即可。
匹配的时候只会进行超过 p p p的扩展,所以是线性算法。
int Next[maxn],extend[maxn];
char s[1000050],t[1000050];
void getNext(char* str){
int i=0,j,pos,len=strlen(str);
Next[0]=len;
while(str[i]==str[i+1]&&i+1<len)i++;Next[1]=i;
pos=1;
for(int i=2;i<len;i++){
if(Next[i-pos]+i<Next[pos]+pos){
Next[i]=Next[i-pos];
}
else{
j=Next[pos]+pos-i;
if(j<0)j=0;//如果i比最远的的小,说明得从头开始。
while(i+j<len&&str[j]==str[j+i])j++;Next[i]=j;
pos=i;
}
}
}
void Exkmp(char* s,char* t){
int i=0,j,pos,l1=strlen(s),l2=strlen(t);
getNext(t);
while(s[i]==t[i]&&i<l1&&i<l2)i++;extend[0]=i;
pos=0;
for(int i=1;i<l1;i++){
if(Next[i-pos]+i<extend[pos]+pos)
extend[i]=Next[i-pos];
else{
j=extend[pos]+pos-i;
if(j<0)j=0;
while(i+j<l1&&j<l2&&s[i+j]==t[j])j++;extend[i]=j;
pos=i;
}
}
}