萌新新学 SAM
报错报了 SIGSEGV /kk
求调/kel
// wish to get better qwq
#include<bits/stdc++.h>
#define re register int
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define dec(x) fixed<<setprecision(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
template<class T> inline void rd(T &x){
int fl=1;x=0;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') fl=-fl;
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
x*=fl;
}
template<class T> inline void wr(T x){
if(x<0) x=-x,putchar('-');
if(x<10){putchar(x+'0');return ;}
int tmp[30]={0},cnt=0;
while(x) tmp[cnt++]=x%10,x/=10;
for(re i=cnt-1;i>=0;--i) putchar(tmp[i]+'0');
}
// ---------- IO ---------- //
const int N=2e6+5;// 记得开字符串长度两倍大小qwq
string s,t;
int op,Tt,n,mx[N],mn[N];
struct Suffix_Automaton{
int tot,lst,maxlen[N],minlen[N],link[N],to[N][26],siz[N],in[N],tp[N],cntlen[N],ss[N];ll cntd,cntsum;queue<int> q;
Suffix_Automaton(){tot=lst=1;}
inline void clear(){
for(re i=1;i<=tot;++i){
maxlen[i]=minlen[i]=link[i]=siz[i]=in[i]=tp[i]=cntlen[i]=ss[i]=0;
for(re j=0;j<26;++j) to[i][j]=0;
}
tot=lst=1;cntd=cntsum=0;
}
inline void insert(int ch){
re nw=++tot,p=lst;siz[nw]=1;maxlen[nw]=maxlen[lst]+1;
while(p&&!to[p][ch]) to[p][ch]=nw,p=link[p];
if(!p) link[nw]=1;
else{
int t=to[p][ch];
if(maxlen[p]+1==maxlen[t]) link[nw]=t;
else{
int cp=++tot;maxlen[cp]=maxlen[p]+1;
for(re i=0;i<26;++i) to[cp][i]=to[t][i];
while(p&&to[p][ch]==t) to[p][ch]=cp,p=link[p];
link[cp]=link[t];link[t]=link[nw]=cp;
}
}
lst=nw;cntd+=maxlen[nw]-maxlen[link[nw]];cntsum=1ll*maxlen[nw]*(maxlen[nw]+1)/2-1ll*maxlen[link[nw]]*(maxlen[link[nw]]+1)/2;
}
inline bool check(char s[],int n){
int nw=1,i=1;
for(;s[i];nw=to[nw][s[i]-'a'],++i)
if(!to[nw][s[i]-'a']) break;
return i==n;
}// 判断模式串是否在原串中出现
inline void topo(){
for(re i=2;i<=tot;++i) ++in[link[i]];
for(re i=1;i<=tot;++i) if(!in[i]) q.push(i);
while(!q.empty()){
int x=q.front();q.pop();
siz[link[x]]+=siz[x];
if(!(--in[link[x]])) q.push(link[x]);
}
}// 拓扑排 个人比较喜欢写的好看的版本(
inline void topo2(){
for(re i=1;i<=tot;++i) ++cntlen[maxlen[i]];
for(re i=1;i<=tot;++i) cntlen[i]+=cntlen[i-1];
for(re i=1;i<=tot;++i) tp[cntlen[maxlen[i]]--]=i;
// for(re i=tot;i>0;--i) siz[link[tp[i]]]+=siz[tp[i]];
// for(re i=1;i<=tot;++i) ss[i]=op?siz[i]:siz[i]=1;siz[1]=ss[1]=0;
// for(re i=tot;i>0;--i)
// for(re j=0;j<26;++j) ss[tp[i]]+=ss[to[tp[i]][j]];
}// 拓扑排 用处比较多的版本 事实上是按 maxlen 从小到大排 效果一样(
// 其中 op=0 时不同位置的相同子串算作一个 op=1 时不同位置的相同子串算作多个
inline ll count(){
/*topo();return siz[1]-1;*/return cntd;
}// 原串不同子串个数
inline ll count2(){
return cntsum;
}// 原串不同子串长度和
inline void kth(int x,int k){
if(ss[1]<k){puts("-1");return ;}
if(k<=siz[x]){puts("");return ;}k-=siz[x];
for(re i=0;i<26;++i)
if(to[x][i]){
if(k>ss[to[x][i]]) k-=ss[to[x][i]];
else{putchar('a'+i);kth(to[x][i],k);return ;}
}
}// 字典序第 k 小的子串
inline int count3(char s[],int n){
topo();
int nw=1,i=1;
for(;s[i];nw=to[nw][s[i]-'a'],++i)
if(!to[nw][s[i]-'a']) break;
if(i<n) return 0;
return siz[nw];
}// 计算模式串出现次数
inline string LCS(string T){
int nw=1,l=0,ans=0,pos=0;
for(re i=0;i<T.size();++i){
while(nw&&!to[nw][T[i]-'a']) nw=link[nw],l=maxlen[nw];
if(!nw) nw=1,l=0;
if(to[nw][T[i]-'a']) nw=to[nw][T[i]-'a'],++l;
if(l>ans) ans=l,pos=i;mx[nw]=max(mx[nw],l);
}
topo2();
for(re i=tot;i>0;--i) mx[link[tp[i]]]=max(mx[link[tp[i]]],min(mx[tp[i]],maxlen[link[tp[i]]]));
for(re i=1;i<=tot;++i) mn[i]=min(mn[i],mx[i]),mx[i]=0;
return T.substr(pos-ans+1,ans);
}// 两个字符串的最长公共子串 其中 mx 和 mn 用来维护多字符串最长公共子串
inline void solve(){
int ans=0;topo();
for(re i=1;i<=tot;++i) if(siz[i]>1) ans=max(ans,siz[i]*maxlen[i]);
wr(ans);puts("");
}// 板子题的 solve 求所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值
}SAM;
// ---------- Suffix Automaton ---------- //
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
for(re i=1;i<N;++i) mn[i]=N;
cin>>s;int ans=0;
for(re i=0;i<s.size();++i) SAM.insert(s[i]-'a');
while(cin>>t) SAM.LCS(t);
for(re i=0;i<SAM.tot;++i) ans=max(ans,mn[i]);
cout<<ans<<endl;
return 0;
}
// ---------- Main ---------- //