思路:将两个串连成一个,跑一比那后缀数组求出height,二分答案ans,如果height[i]>=ans,sa[i]和sa[i-1]分别在两个串中就行
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
///**后缀数组
///**可重叠最长重复字串:max(height[i])
///**不可重叠最长重复字串:二分答案,一段连续的height[i]>=k,sa(max)-sa[min)>=k -> true;
const int maxn=2e5+10;
int sa[maxn],Rank[maxn],height[maxn],tp[maxn],a[maxn],tax[maxn];
///**sa[i]:排序后的第i个后缀的位置
///**Rank[i]:第i个后缀的排名
///**height[i]:第i个后缀和第i-1个后缀的最长公共前缀的长度
int len,m,k;
char str[maxn];
void Rsort()
{
for(int i=0;i<=m;i++) tax[i]=0;
for(int i=1;i<=len;i++) tax[Rank[tp[i]]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(int i=len;i>=1;i--) sa[tax[Rank[tp[i]]]--]=tp[i];
}
int cmp(int *f,int x,int y,int w){return (f[x]==f[y])&&(f[x+w]==f[y+w]);}
void Suffix()
{
for(int i=1;i<=len;i++) Rank[i]=a[i],tp[i]=i;
m=200;///**根据数组存的数字的大小要进行调整
Rsort();
for(int w=1,p=1,i;p<len;w+=w,m=p){
for(p=0,i=len-w+1;i<=len;i++) tp[++p]=i;
for(i=1;i<=len;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
Rsort();swap(Rank,tp);Rank[sa[1]]=p=1;
for(i=2;i<=len;i++) Rank[sa[i]]=cmp(tp,sa[i],sa[i-1],w)?p:++p;
}
for(int i=1;i<=len;i++) Rank[sa[i]]=i;
int j,k=0;
for(int i=1;i<=len;height[Rank[i++]]=k)
for(k=k?k-1:k,j=sa[Rank[i]-1];a[i+k]==a[j+k];++k);
}
void init()
{
len=strlen(str);
for(int i=0;i<len;i++) a[i+1]=str[i];
}
char s[maxn];
int l;
bool check(int x)
{
for(int i=2;i<=len;i++){
if(height[i]>=x&&(sa[i-1]<=l&&sa[i]>l||sa[i-1]>l&&sa[i]<=l)) return true;
}
return false;
}
inline int solve()
{
int l=0,r=len,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
return ans;
}
int main()
{
scanf("%s%s",str,s);
l=len=strlen(str);
for(int i=0;s[i];i++) str[len++]=s[i];
str[len]='\0';
init();
Suffix();
printf("%d\n",solve());
return 0;
}