蒟蒻的第一道后缀数组的题目!!
SA是个好东西,本题就是考察它的经典应用——求一个字符串里面两个后缀的最长公共前缀!
所以我们就可以考虑把两个字符串拼起来,然后查找两个后缀,使得他们的最长公共前缀最长。
然后就是板子了吧qwqwq(感觉SA的写法和网上很多人的不一样??不过原理还是一样的啦qwq)
不会SA的可以参考自为风月马前卒大佬的blog,讲的真的很详细:戳我
需要注意的一点就是最后查询的时候一定要保证两个后缀的起始位置下标不能在同一个子串里,怎么处理呢?一个简单的方法是构建字符串的时候就在两个字符串中间加入一个根本就不会出现的字符。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 300010
using namespace std;
int len1,len2,n,ans,m;
int tag[MAXN],h[MAXN],tax[MAXN],s[MAXN],rnk[MAXN],tp[MAXN],sa[MAXN];
char s1[MAXN],s2[MAXN];
inline void qsort()
{
for(int i=1;i<=m;i++) tax[i]=0;
for(int i=1;i<=n;i++) tax[rnk[i]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(int i=n;i>=1;i--) sa[tax[rnk[tp[i]]]--]=tp[i];
}
inline void suffixsort()
{
m=75;
for(int i=1;i<=n;i++) rnk[i]=s[i],tp[i]=i;
qsort();
for(int w=1,p=0;p<n;m=p,w<<=1)
{
p=0;
for(int i=1;i<=w;i++) tp[++p]=n-w+i;
for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
qsort();
swap(tp,rnk);
rnk[sa[1]]=p=1;
for(int i=2;i<=n;i++) rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]])&&(tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
}
}
inline void get_h()
{
int hi=0,j;
for(int i=1;i<=n;i++)
{
j=sa[rnk[i]-1];
if(hi>0) hi--;
for(;j+hi<=n&&i+hi<=n;hi++)
if(s[i+hi]!=s[j+hi]) break;
h[rnk[i]-1]=hi;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%s",s1+1),scanf("%s",s2+1);
len1=strlen(s1+1),len2=strlen(s2+1);
n=len1+len2+1;
for(int i=1;i<=len1;i++) s[i]=s1[i]-'a'+1;
s[len1+1]=30;
for(int i=1;i<=len2;i++) s[i+len1+1]=s2[i]-'a'+1;
suffixsort();
get_h();
for(int i=1;i<n;i++)
if((sa[i]<=len1)!=(sa[i+1]<=len1))
ans=max(ans,h[i]);
printf("%d\n",ans);
return 0;
}
原文:https://www.cnblogs.com/fengxunling/p/10235820.html