【学习笔记】exkmp(Z函数)
本文参考洛谷题解:https://www.luogu.com.cn/article/cq4b4e5f
侵删
前言
exkmp 和 kmp 要求的东西比较类似。
exkmp 可以求出
a
i
.
.
.
n
a_{i...n}
ai...n 和
b
b
b 的最长公共前缀。
这玩意也称 z 函数。
算法流程
求解 nxt 数组
定义
n
x
t
i
nxt_i
nxti 为
∣
l
c
p
(
b
i
.
.
n
,
b
)
∣
|lcp(b_{i..n},b)|
∣lcp(bi..n,b)∣,也就是
s
s
s 每一段后缀和自身的最长公共前缀。
例如:
那这玩意怎么求呢?
假设
n
x
t
0...
x
−
1
nxt_{0...x-1}
nxt0...x−1 已经求出,考虑如何求
n
x
t
x
nxt_x
nxtx
还记得
M
a
n
a
c
h
e
r
Manacher
Manacher 是怎么做的吗?你要找到最靠右的回文串,然后用它的信息求当前回文半径。
类似的,对于所有的
1
≤
x
<
n
1\leq x < n
1≤x<n 我们要求出
i
+
n
x
t
i
−
1
i+nxt_i-1
i+nxti−1 的最大值,记最大值编号为
k
k
k,记
p
=
k
+
n
x
t
k
−
1
p=k+nxt_k-1
p=k+nxtk−1。
为什么不是
0
≤
x
<
n
0 \leq x <n
0≤x<n?因为
n
x
t
0
nxt_0
nxt0 一定等于
n
n
n,这样子就没什么意义了。
根据定义,我们可以得到
b
0...
n
x
t
k
−
1
=
=
b
k
.
.
.
p
b_{0...nxt_k-1}==b_{k...p}
b0...nxtk−1==bk...p 。如图,蓝色部分相等:
于是,我们就可以推出:
b
x
−
k
.
.
.
n
x
t
k
−
1
=
b
x
.
.
.
p
b_{x-k...nxt_k-1}=b_{x...p}
bx−k...nxtk−1=bx...p
我们最终的目的是求出
n
x
t
x
nxt_x
nxtx,
x
x
x 对应的位置是
x
−
k
x-k
x−k,所以我们要根据
x
−
k
x-k
x−k 判断
x
x
x能跳多远。
令
l
=
n
x
t
x
−
k
l=nxt_{x-k}
l=nxtx−k,如果
x
−
k
+
l
−
1
x-k+l-1
x−k+l−1 还在绿色区域范围内,也就是
x
−
k
+
l
−
1
≤
n
x
t
k
−
1
x-k+l-1\leq nxt_k-1
x−k+l−1≤nxtk−1,那么
b
x
−
k
.
.
.
x
−
k
+
l
−
1
=
=
b
x
.
.
.
x
+
l
−
1
b_{x-k...x-k+l-1}==b_{x...x+l-1}
bx−k...x−k+l−1==bx...x+l−1。如图,灰色部分相等:
但是如果它超出了绿色部分,超出的部分就不能保证相等了,要暴力匹配。如图:
这个过程是不是和Manacher一毛一样?
vector<int> getNext(string &s)
{
vector<int> nxt(s.size());
int p=0; //furthest position p=k+nxt[k]-1
int k=1; //furthest position id
nxt[0]=s.size();
while(p+1<s.size()&&s[p]==s[p+1])
p++;
nxt[1]=p;
for(int i=2; i<s.size(); i++)
{
p=k+nxt[k]-1;
int l=nxt[i-k]; //if i+l<=p then [i,i+l-1] == [i-k,i-k+l-1]
if(i+l<=p)
nxt[i]=l;
else
{
int j=max(0ll,p-i+1);
while(i+j<s.size()&&s[i+j]==s[j])
j++;
nxt[i]=j;
k=i;
}
}
return nxt;
}
求解 extend 数组(z函数)
和求解
n
x
t
nxt
nxt 数组的过程类似。
vector<int> getExtend(string &s,string &t,vector<int> &nxt)
{
int p=0,k=0;
while(p<s.size()&&p<t.size()&&s[p]==t[p])
p++;
vector<int> ext(s.size());
ext[0]=p;
for(int i=1; i<s.size(); i++)
{
p=k+ext[k]-1;
int l=nxt[i-k];
if(i+l<=p)
ext[i]=l;
else
{
int j=max(0ll,p-i+1);
while(i+j<s.size()&&j<t.size()&&s[i+j]==t[j])
j++;
ext[i]=j;
k=i;
}
}
return ext;
}
【模板】扩展 KMP/exKMP(Z 函数)
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+7,inf=1e18;
vector<int> getNext(string &s)
{
vector<int> nxt(s.size());
int p=0; //furthest position p=k+nxt[k]-1
int k=1; //furthest position id
nxt[0]=s.size();
while(p+1<s.size()&&s[p]==s[p+1])
p++;
nxt[1]=p;
for(int i=2; i<s.size(); i++)
{
p=k+nxt[k]-1;
int l=nxt[i-k]; //if i+l<=p then [i,i+l-1] == [i-k,i-k+l-1]
if(i+l<=p)
nxt[i]=l;
else
{
int j=max(0ll,p-i+1);
while(i+j<s.size()&&s[i+j]==s[j])
j++;
nxt[i]=j;
k=i;
}
}
return nxt;
}
vector<int> getExtend(string &s,string &t,vector<int> &nxt)
{
int p=0,k=0;
while(p<s.size()&&p<t.size()&&s[p]==t[p])
p++;
vector<int> ext(s.size());
ext[0]=p;
for(int i=1; i<s.size(); i++)
{
p=k+ext[k]-1;
int l=nxt[i-k];
if(i+l<=p)
ext[i]=l;
else
{
int j=max(0ll,p-i+1);
while(i+j<s.size()&&j<t.size()&&s[i+j]==t[j])
j++;
ext[i]=j;
k=i;
}
}
return ext;
}
void O_o()
{
string s,t;
cin>>s>>t;
auto nxt=getNext(t);
auto ext=getExtend(s,t,nxt);
int a=0,b=0;
for(int i=0; i<nxt.size(); i++)
{
a^=(i+1)*(nxt[i]+1);
}
for(int i=0; i<ext.size(); i++)
{
b^=(i+1)*(ext[i]+1);
}
cout<<a<<"\n"<<b<<"\n";
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cout<<fixed<<setprecision(12);
int T=1;
// cin>>T
while(T--)
{
O_o();
}
}