反正clj的ppt都讲了
- LCS的话……因为只需要匹配一次,也就不需要更新pre的值了。
- 然而LCS2……因为有多个字符串要匹配,于是要把整个SAM上的rec都更新了,所以多了一步从后往前更新的
至于【rec[pre[k]]=dis[pre[k]]】……是因为……parent树的性质……max[pre[k]]=dis[pre[k]]<min[k],而既然k是可达的,说明pre上子串长度的任意取值都是可达的(原理就是对于某个状态i,i可以表示的串长度肯定比它在parent树上的父节点能表示的最大长度更大……l[i]>r[pre[i]])【woc好难解释啊QAQ,反正就是那个意思】
LCS ↓
#include<bits/stdc++.h>
#define MAXN 500057
//#define FLAZE_NAIVE
using namespace std; char read_s[MAXN];
struct sam{
int son[MAXN][26],pre[MAXN],dis[MAXN];
int lst,cnt,lth;
int p,q,np,nq;
void insert(int x){
dis[np=++cnt]=dis[p=lst]+1;
lst=np;
for(;p&&!son[p][x];p=pre[p]) son[p][x]=np;
if(!p) return pre[np]=1,void();
q=son[p][x];
if(dis[q]==dis[p]+1) pre[np]=q;
else{
dis[nq=++cnt]=dis[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
for(;p&&son[p][x]==q;p=pre[p]) son[p][x]=nq;
}
}
void build(){
cnt=lst=1;
scanf("%s",read_s);
lth=strlen(read_s);
for(int i=0;i<lth;++i) insert(read_s[i]-'a');
}
#ifdef FLAZE_NAIVE
char tmp[MAXN];
void dfs(int now,int stp){
for(int i=0;i<26;++i)
if(son[now][i]){
tmp[stp]='a'+i;
puts(tmp);
dfs(son[now][i],stp+1);
}
tmp[stp]=' ';
}
#endif
int ans;
void check(){
ans=0;
int now=1,tmp=0;
scanf("%s",read_s);
int str_len=strlen(read_s);
for(int i=0;i<str_len;++i){
int x=read_s[i]-'a';
if(son[now][x])
++tmp,now=son[now][x];
else{
for(;now&&!son[now][x];now=pre[now]);
if(!now)
now=1,tmp=0;
else
tmp=dis[now]+1,
now=son[now][x];
}
ans=max(ans,tmp);
}
}
}SAM_s;
int main(){
SAM_s.build();
// SAM_s.dfs(1,0);
SAM_s.check();
printf("%d",SAM_s.ans);
return 0;
}
LCS2 ↓
#include<bits/stdc++.h>
#define MAXN 200057
#define INF 0x3f3f3f3f
//#define FLAZE_NAIVE
using namespace std; char read_s[MAXN>>1];
struct t1{
int son[MAXN][26],pre[MAXN],dis[MAXN];
int cnt,lst;
int lth;
int p,np,q,nq;
void insert(int x){
dis[np=++cnt]=dis[p=lst]+1;
lst=np;
for(;p&&!son[p][x];p=pre[p]) son[p][x]=np;
if(!p) return pre[np]=1,void();
q=son[p][x];
if(dis[q]==dis[p]+1) pre[np]=q;
else{
dis[nq=++cnt]=dis[p]+1;
memcpy(son[nq],son[q],sizeof son[q] );
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
for(;p&&son[p][x]==q;p=pre[p]) son[p][x]=nq;
}
}
void build(){
lst=cnt=1;
scanf("%s",read_s);
lth=strlen(read_s);
for(int i=0;i<lth;++i) insert(read_s[i]-'a');
}
#ifdef FLAZE_NAIVE
char tmp[MAXN>>1];
void dfs(int now,int stp){
for(int i=0;i<26;++i)
if(son[now][i]){
tmp[stp]=97+i;
puts(tmp);
dfs(son[now][i],stp+1);
}
tmp[stp]=' ';
}
#endif
int s[MAXN],v[MAXN];
void sort(){
for(int i=1;i<=cnt;++i) ++v[dis[i]];
for(int i=1;i<=lth;++i) v[i]+=v[i-1];
for(int i=1;i<=cnt;++i) s[v[dis[i]]--]=i;
}
int ans;
int rec[MAXN];
int pre_rec[MAXN];
void check(){
memset(rec,0,sizeof rec);
int tmp=0,now=1;
int l2=strlen(read_s);
for(int i=0;i<l2;++i){
int x=read_s[i]-'a';
if(son[now][x])
now=son[now][x],++tmp;
else{
for(;now&&!son[now][x];now=pre[now]);
if(!now)
now=1,tmp=0;
else{
tmp=dis[now]+1;
now=son[now][x];
}
}
rec[now]=max(rec[now],tmp);
}
for(int i=cnt;i;--i){
int k=s[i];
pre_rec[k]=min(pre_rec[k],rec[k]);
if(rec[k]&&pre[k]) rec[pre[k]]=dis[pre[k]];
}
}
}SAM_s;
int main(){
SAM_s.build();
// SAM_s.dfs(1,0);
SAM_s.sort();
memset(SAM_s.pre_rec,INF,sizeof SAM_s.pre_rec);
while(~scanf("%s",read_s))
SAM_s.check();
for(int i=1;i<=SAM_s.cnt;++i) SAM_s.ans=max(SAM_s.ans,SAM_s.pre_rec[i]);
printf("%d",SAM_s.ans);
return 0;
}