题意:
求a b两个串的最短公共子串长度,且这个子串在a串只出现过一次,在b串也只出现过一次
题解:
先把ab两个串连在一起形成一个新的串,中间用‘ ’空格符号隔开,用来区分两个串。
先跑一下后缀数组,利用height数组来求解。在i,向左找到第一个j1使,height[j1]<height[i],向右找到第一个j2,
使height[j2]<height[i]。j2-j1-1的值等于长度为height[i]的串出现了多少次。题目要求在各串只出现了一次的公共子串,这两个字串在sa数组里一定是相邻的,即sa[i],sa[i-1],且满足
1,sa[i]和sa[i-1]属于原先不同的串
2.串sa[i-2]和串sa[i-1]的公共子串长度和串sa[i]和串sa[i+1]的公共子串长度小于串sa[i-1]和串sa[i]的公共子串长度,即
height[i-1]<height[i]&&height[i]>height[i+1]
此时,max(height[i-1],height[i+1])+1为合法长度
例如
height
0 abc
3 abcd
2 abdd
此时有效的字串是abc
#include<iostream>
#include<cstdio>
#include<cstring>
#define rint register int
#define inv inline void
#define ini inline int
#define maxn 1000050
using namespace std;
char s[maxn];
int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[30];
int n,m;
inv putout(int x) {
if(!x) {
putchar(48);
return;
}
rint l=0;
while(x) wt[++l]=x%10,x/=10;
while(l) putchar(wt[l--]+48);
}
inv get_SA() {
for (rint i=1; i<=n; ++i) ++c[x[i]=s[i]];
for (rint i=2; i<=m; ++i) c[i]+=c[i-1];
for (rint i=n; i>=1; --i) sa[c[x[i]]--]=i;
for (rint k=1; k<=n; k<<=1) {
rint num=0;
for (rint i=n-k+1; i<=n; ++i) y[++num]=i;
for (rint i=1; i<=n; ++i) if (sa[i]>k) y[++num]=sa[i]-k;
for (rint i=1; i<=m; ++i) c[i]=0;
for (rint i=1; i<=n; ++i) ++c[x[i]];
for (rint i=2; i<=m; ++i) c[i]+=c[i-1];
for (rint i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y);
x[sa[1]]=1;
num=1;
for (rint i=2; i<=n; ++i)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;
if (num==n) break;
m=num;
}
}
inv get_height() {
rint k=0;
for (rint i=1; i<=n; ++i) rk[sa[i]]=i;
for (rint i=1; i<=n; ++i) {
if (rk[i]==1) continue;//第一名height为0
if (k) --k;//h[i]>=h[i-1]-1;
rint j=sa[rk[i]-1];
while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;//h[i]=height[rk[i]];
}
}
int belong[maxn];
int main() {
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++){
belong[i]=1;
}
s[++n]=' ';
scanf("%s",&s[n+1]);
int st2=n+1;
n+=strlen(&s[n+1]);
for(int i=st2;i<=n;i++) belong[i]=2;
m=200;
get_SA();
get_height();
int mi=10000;
for(int i=1;i<=n;i++){
if(belong[sa[i-1]]+belong[sa[i]]==3){
if(height[i-1]<height[i]&&height[i]>height[i+1]){
mi=min(mi,max(height[i-1],height[i+1])+1);
}
}
}
if(mi==10000) mi=-1;
printf("%d\n",mi);
}