table of Contents
KMP string
Substring: Select a continuous segment from the original string, which is the
prefix of the substring (including the empty string) : pre (s, k) pre(s,k)p r e ( s ,k ) is thesuffix of thesubstring formed by thefirstk characters ofs
: suf (s, k) suf(s,k)suf(s,k ) is a substring composed of s(k...n)
Any substring is a prefix of a certain suffix. The
longest common prefixlcp (s, t) lcp(s,t)lcp(s,t ) and the longest common suffixlcs (s, t) lcs(s,t)lcs(s,t)
周期: ① 0 < p < ∣ s ∣ 0<p<|s| 0<p<∣s∣ ② s [ i ] = s [ i + p ] , ∀ i ∈ { 1 , 2 , … , ∣ s ∣ − p } s[i]=s[i+p], \forall i\in\{1,2,\dots,|s|-p\} s[i]=s[i+p],∀i∈{ 1,2,…,∣s∣−p } , meet the above conditions, calledppp is the period
Borderof s:①0 <r <∣ s ∣ 0<r<|s|0<r<∣s∣ ② p r e ( s , r ) = s u f ( s , r ) pre(s,r)=suf(s,r) p r e ( s ,r)=suf(s,r ) , meet the above conditions, callpre (s, r) pre(s,r)p r e ( s ,r ) is
the relationship betweenthe borderperiodof s and the border:pre (s, k) pre(s,k)p r e ( s ,k ) is the border⇔ \Leftrightarrow of s⇔ | s | - k | s | -k∣s∣−k is
the transitivity ofthe periodic
border of s:①string s is the border of t, and string t is the border of r, then s is the border of r ②string
s is the border of r, and the string t (∣ t ∣> ∣ s ∣ | t|>|s|∣t∣>∣ s ∣ ) is also the border of r, then s is the border of t, and
mb(s) represents the longest border of s. Then mb(s), mb(mb(s))... all the borders that constitute s
Given a pattern string S and a template string P, all strings only contain uppercase and lowercase English letters and Arabic numerals.
The template string P appears as a substring multiple times in the pattern string S.
Calculate the initial index (starting from 0) of all the positions of the template string P in the pattern string S.
#include<iostream>
using namespace std;
const int N=1000010;
int n,m;
char p[N],s[N];
int ne[N];
int main()
{
cin>>n>>p+1>>m>>s+1;
// 求ne过程看成两个相同的串匹配
for(int i=2,j=0;i<=n;i++)
{
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;// i结尾能够匹配 1~j 那么ne[i]=j
ne[i]=j;
}
// 当前需要判断是否匹配 p[j+1]?=s[i]
for(int i=1,j=0;i<=m;i++)
{
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==n)
{
cout<<i-n<<' ';
j=ne[j];
}
}
return 0;
}
Fail mismatch tree
Concept and construction: Regarding next[i] as the parent node of point i , then the 0~N points can be connected into a tree through the next array, which satisfies the properties:
- All ancestors of point i are borders with prefix pre(s,i)
- Two points i and j without ancestor relationship have no border relationship
Connection: The process of calculating next[i] can be seen as: starting from j=fa[i-1] and going up continuously, find the first point that satisfies s[j+1]=s[i], and put point i Set the father to j+1
#include<string>
#include<iostream>
using namespace std;
const int N=1000010;
int ne[N];
int fa[N][21],dep[N];
string s;
int n;
int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
for(int k=20;k>=0;k--)
if(dep[fa[a][k]]>=dep[b]) a=fa[a][k];
if(a==b) return a;
for(int k=20;k>=0;k--)
if(fa[a][k]!=fa[b][k])
{
a=fa[a][k];
b=fa[b][k];
}
return fa[a][0];
}
int main()
{
cin>>s;
n=s.size();
s="."+s;
dep[0]=1,dep[1]=2;
fa[1][0]=0;
for(int i=2,j=0;i<=n;i++)
{
while(j&&s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
// 构建失配树
fa[i][0]=j;dep[i]=dep[j]+1;
for(int k=1;k<=20;k++)
fa[i][k]=fa[fa[i][k-1]][k-1];
}
int q;
cin>>q;
while(q--)
{
int a,b;
cin>>a>>b;
int pab=lca(a,b);
// 注意本身是公共祖先的情况
if(a==pab||b==pab) cout<<ne[pab]<<'\n';
else cout<<pab<<'\n';
}
return 0;
}