最长公共子串
给出两个长度小于1e5的串,求它们的最长公共子串。
当然是用后缀数组辣,把两个串拼起来,中间加个@符号,再求最长重复子串,处理一下即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2e5+5;
char s[maxn];
int n, orin, ans, m=maxn, sa[maxn], ht[maxn];
int *x, *y, *t, wa[maxn], wb[maxn], ws[maxn], wv[maxn];
bool cmp(int *r, int a, int b, int l){
return r[a]==r[b]&&r[a+l]==r[b+l]; }
void Ssort(char *r){
int i, j, p=0; x=wa; y=wb; m=maxn;
memset(ws, 0, sizeof(ws));
for (i=0; i<n; ++i) ++ws[x[i]=r[i]];
for (i=1; i<m; ++i) ws[i]+=ws[i-1];
for (i=0; i<n; ++i) sa[--ws[r[i]]]=i;
for (j=1; j<n&&p<n; j<<=1, m=p+1){
for (p=0, i=n-j; i<n; ++i) y[p++]=i;
for (i=0; i<n; ++i) if (sa[i]>=j) y[p++]=sa[i]-j;
for (i=0; i<n; ++i) wv[i]=x[y[i]];
for (i=0; i<m; ++i) ws[i]=0;
for (i=0; i<n; ++i) ++ws[x[i]];
for (i=1; i<m; ++i) ws[i]+=ws[i-1];
for (i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i];
t=x; x=y; y=t; x[sa[0]]=1;
for (p=1, i=1; i<n; ++i)
x[sa[i]]=cmp(y, sa[i-1], sa[i], j)?p:++p;
}
for (i=0; i<n; ++i) --x[i]; p=0;
for (i=0; i<n; ht[x[i++]]=p){
if (!x[i]){ p=0; continue; }
for (p?p--:0, j=sa[x[i]-1]; r[i+p]==r[j+p]&&i+p<n; ++p);
}
return;
}
int main(){
scanf("%s", s); n=orin=strlen(s); //s[orin]='@'
s[n++]='@'; scanf("%s", s+n); n=strlen(s);
Ssort(s);
for (int i=1; i<n; ++i)
if (sa[i]<orin&&sa[i-1]>orin
||sa[i]>orin&&sa[i-1]<orin)
ans=max(ans, ht[i]);
printf("%d
", ans);
return 0;
}