传送门:bzoj3145
题解
完全是膜着Claris的code写的,代码就不用看了。。。
不考虑复杂度我们可以枚举
i
,
j
i,j
i,j分别表示串
S
,
T
S,T
S,T中那个不同的位置。
则
a
n
s
=
m
a
x
(
l
c
s
(
i
−
1
,
j
−
1
)
+
l
c
p
(
i
+
1
,
j
+
1
)
)
+
1
ans=max(lcs(i-1,j-1)+lcp(i+1,j+1))+1
ans=max(lcs(i−1,j−1)+lcp(i+1,j+1))+1
可以在 S S S末尾加一个字符集外的字符后再连上 T T T。正着求出 l c p lcp lcp翻转后求出 l c s lcs lcs。
可以通过固定一维枚举另一维 O ( n 2 ) O(n^2) O(n2)的复杂度降到 O ( n log n ) O(n\log n) O(nlogn):从大到小枚举 l c p lcp lcp的值,即按 h e i g h t i height_i heighti排序,并查集维护 h e i g h t ≥ l c p height\geq lcp height≥lcp的连续区间启发式合并 i − 1 , i i-1,i i−1,i所在的区间,逐个插入更新答案。
每段连续区间中 s e t set set维护这些串对应的在 S , T S,T S,T中的 l c s lcs lcs的 r a n k rank rank,对于插入的串找到集合中最接近它对应的前缀 r a n k rank rank求个 l c s lcs lcs即可。
注意以上都是强制 l c s , l c p lcs,lcp lcs,lcp均 > 0 >0 >0的情况,还有可能只有 l c s / l c p lcs/lcp lcs/lcp,需要最后特殊枚举判断一下。
代码
#include<bits/stdc++.h>
#define mem(f) memset(f,0,sizeof(f))
using namespace std;
const int N=4e5+100;
int n,la,lb,d[18][N],bin[30],lg[N],id[N],sz[N];
int c[N],t1[N],t2[N],f[N],ans,lcp;
int head[N],nxt[N<<1],to[N<<1],tot;
char s[N],t[N];bool ca[N],cb[N];
set<int>sa[N],sb[N];
set<int>::iterator it;
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
struct SA{
int sa[N],rk[N],ht[N];char s[N];
inline void build()
{
int i,j,k,p,m=128,*x=t1,*y=t2;
for(i=1;i<=n;++i) c[(x[i]=(int)s[i])]++;
for(i=1;i<=m;++i) c[i]+=c[i-1];
for(i=n;i;--i) sa[c[x[i]]--]=i;
for(k=1;k<=n;k<<=1){
for(p=0,i=n-k+1;i<=n;++i) y[++p]=i;
for(i=1;i<=n;++i) if(sa[i]>k) y[++p]=sa[i]-k;
for(i=1;i<=m;++i) c[i]=0;
for(i=1;i<=n;++i) c[x[y[i]]]++;
for(i=1;i<=m;++i) c[i]+=c[i-1];
for(i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
p=1;swap(x,y);x[sa[1]]=1;
for(i=2;i<=n;++i){
p+=((y[sa[i]]!=y[sa[i-1]])||(y[sa[i]+k]!=y[sa[i-1]+k]));
x[sa[i]]=p;
}
if(p>=n) break;
m=p;
}
for(i=1;i<=n;++i) rk[sa[i]]=i;
for(p=0,i=1;i<=n;++i){
if(rk[i]==1) {p=0;continue;}
for(p=max(0,p-1),j=sa[rk[i]-1];i+p<=n && j+p<=n && s[i+p]==s[j+p];++p);
ht[rk[i]]=p;
}
}
inline void mk()
{
int i,j;bin[0]=1;
for(i=1;i<30;++i) bin[i]=bin[i-1]<<1;
for(i=2;i<N;++i) lg[i]=lg[i>>1]+1;
for(i=1;i<=n;++i) d[0][i]=ht[i];
for(i=1;bin[i]<=n;++i)
for(j=1;j+bin[i]-1<=n;++j)
d[i][j]=min(d[i-1][j],d[i-1][j+bin[i-1]]);
}
}A,B;
inline int cal(int x,int y)
{
if(x>y) swap(x,y);int bs=lg[y-x];
return min(d[bs][x+1],d[bs][y-bin[bs]+1]);
}
void dfs(int x,int fr,int bl)
{
int i,j;f[x]=bl;
if(A.sa[x]<=la){
i=A.sa[x]-2;if(i>0){
i=B.rk[n-i+1];sa[bl].insert(i);
it=sb[bl].lower_bound(i);
if(it!=sb[bl].end()) ans=max(ans,lcp+cal(i,*it));
if(it!=sb[bl].begin()) it--,ans=max(ans,lcp+cal(i,*it));
}
}else if(A.sa[x]>la+1){
i=A.sa[x]-2;if(i>la+1){
i=B.rk[n-i+1];sb[bl].insert(i);
it=sa[bl].lower_bound(i);
if(it!=sa[bl].end()) ans=max(ans,lcp+cal(i,*it));
if(it!=sa[bl].begin()) it--,ans=max(ans,lcp+cal(i,*it));
}
}
for(i=head[x];i;i=nxt[i]) if(to[i]!=fr) dfs(to[i],x,bl);
}
inline void ext(int x,int y)
{
x=f[x];y=f[y];
if(sz[x]>sz[y]) swap(x,y);
if((ca[x]&&cb[y])||(cb[x]&&ca[y])) ans=max(ans,lcp-1);
ca[y]|=ca[x];cb[y]|=cb[x];sz[y]+=sz[x];
sa[x].clear();sb[x].clear();
lk(x,y);lk(y,x);dfs(x,y,y);
}
inline bool cmp(const int&x,const int&y){return A.ht[x]>A.ht[y];}
int main(){
int i,j;
scanf("%s%s",s+1,t+1);
la=strlen(s+1);lb=strlen(t+1);
if(la==1 || lb==1) {puts("1");return 0;}
s[(n=la+1)]='#';for(i=1;i<=lb;++i) s[++n]=t[i];
for(i=1;i<=n;++i) A.s[i]=B.s[n-i+1]=s[i];
B.build();B.mk();mem(c);mem(t1);mem(t2);A.build();
for(i=1;i<=n;++i) f[i]=i,sz[i]=1;
for(i=1;i<=n;++i){
if(A.sa[i]<=la){
ca[i]=true;j=A.sa[i]-2;
if(j>0) sa[i].insert(B.rk[n-j+1]);
}else if(A.sa[i]>la+1){
cb[i]=true;j=A.sa[i]-2;
if(j>la+1) sb[i].insert(B.rk[n-j+1]);
}
}
for(i=1;i<n;++i) id[i]=i+1;
sort(id+1,id+n,cmp);
for(i=1;i<n;++i) lcp=A.ht[id[i]],ext(id[i]-1,id[i]);
i=A.rk[2];
for(lcp=1e9,j=i-1;j;--j){
lcp=min(lcp,A.ht[j+1]);
if(A.sa[j]>la+2) ans=max(lcp,ans);
}
for(lcp=1e9,j=i+1;j<=n;++j){
lcp=min(lcp,A.ht[j]);
if(A.sa[j]>la+2) ans=max(lcp,ans);
}
i=A.rk[la+3];
for(lcp=1e9,j=i-1;j;--j){
lcp=min(lcp,A.ht[j+1]);
if(A.sa[j]>1&&A.sa[j]<=la) ans=max(lcp,ans);
}
for(lcp=1e9,j=i+1;j<=n;++j){
lcp=min(lcp,A.ht[j]);
if(A.sa[j]>1&&A.sa[j]<=la) ans=max(lcp,ans);
}
i=B.rk[2];
for(lcp=1e9,j=i-1;j;--j){
lcp=min(lcp,B.ht[j+1]);
if(B.sa[j]>lb+2) ans=max(lcp,ans);
}
for(lcp=1e9,j=i+1;j<=n;++j){
lcp=min(lcp,B.ht[j]);
if(B.sa[j]>lb+2) ans=max(lcp,ans);
}
i=B.rk[lb+3];
for(lcp=1e9,j=i-1;j;--j){
lcp=min(lcp,B.ht[j+1]);
if(B.sa[j]>1 && B.sa[j]<=lb) ans=max(lcp,ans);
}
for(lcp=1e9,j=i+1;j<=n;++j){
lcp=min(lcp,B.ht[j]);
if(B.sa[j]>1 && B.sa[j]<=lb) ans=max(lcp,ans);
}
printf("%d",ans+1);
return 0;
}