SP1811 LCS - Longest Common Substring(SAM)
思路:
1.对第一个字符串建立 S A M SAM SAM,然后第二个字符串在 S A M SAM SAM跑,有转移就 a n s + + ans++ ans++,然后 p p p变为他的转移结点,否则跳 f a i l fail fail,若跳到 0 0 0就 a n s = 0 , p = 1 ans=0,p=1 ans=0,p=1,否则更新 a n s = l e n [ p ] + 1 , p = c h [ p ] [ x ] ans=len[p]+1,p=ch[p][x] ans=len[p]+1,p=ch[p][x]。
2.广义 S A M SAM SAM,用 l a s t = 1 last=1 last=1实现,然后将 f a i l [ i ] , i fail[i],i fail[i],i连边建图,跑 S A M SAM SAM的时候储存在每个状态在对应的字符串是否出现过 s z [ n p ] [ o p ] , o p ∈ { 0 , 1 } sz[np][op],op\in\{0,1\} sz[np][op],op∈{0,1}。
然后在图上跑 d f s dfs dfs,取最值。
时间复杂度: O ( ∣ Σ ∣ n ) O(|\Sigma| n) O(∣Σ∣n)
做法1:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false),cin.tie(0)
int n,q;
char a[N],b[N];
struct SAM{
int last,cnt;int ch[N<<1][26],fa[N<<1],len[N<<1];
void insert(int c){
int p=last,np=++cnt;last=np;len[np]=len[p]+1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else {
int nq=++cnt;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
void build(){
last=cnt=1;
scanf("%s",a+1);
for(int i=1;a[i];i++)
insert(a[i]-'a');
scanf("%s",b+1);
int ans=0,p=1,res=0;
for(int i=1;b[i];i++){
int x=b[i]-'a';
if(ch[p][x]) p=ch[p][x],ans++;
else {
while(p&&!ch[p][x]) p=fa[p];
if(!p) p=1,ans=0;
else ans=len[p]+1,p=ch[p][x];
}
if(res<ans) res=ans;
}
printf("%d\n",res);
}
}sam;
int main(){
IOS;
sam.build();
return 0;
}
做法2:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false),cin.tie(0)
int n,q,tot;
char a[N],b[N];
struct SAM{
int last,cnt;int ch[N<<1][26],fa[N<<1],len[N<<1];
int to[N<<1],nt[N<<1],h[N<<1],ans=0;
void add(int u,int v){
to[++tot]=v,nt[tot]=h[u],h[u]=tot;
}
bool sz[N<<1][2];
void insert(int c,int op){
int p=last,np=++cnt;last=np;len[np]=len[p]+1;
sz[np][op]=true;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else {
int nq=++cnt;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
void build(){
last=cnt=1;
scanf("%s",a+1);
for(int i=1;a[i];i++)
insert(a[i]-'a',0);
last=1;
scanf("%s",b+1);
for(int i=1;b[i];i++)
insert(b[i]-'a',1);
for(int i=2;i<=cnt;i++) add(fa[i],i);
}
void dfs(int u){
for(int i=h[u];i;i=nt[i]){
dfs(to[i]);
int v=to[i];
sz[u][0]|=sz[v][0],sz[u][1]|=sz[v][1];
}
if(sz[u][0]&&sz[u][1]) ans=max(ans,len[u]);
}
}sam;
int main(){
IOS;
sam.build();
sam.dfs(1);
printf("%d\n",sam.ans);
return 0;
}