https://www.oj.swust.edu.cn/problem/show/2779
题意中文题不说了。
做法:后缀数组,想把两个串连接起来,求sa和height数组,因为题目要求求的公共子串,而且每一个串只出现一次,所以标记每一个后缀属于哪一个串,遍历heigh数组,然后判断周围有没有height值大于等于当前下标的,如果没有则这个串的是可以取得,
但不过,直接去这个串是不行的,所以应该是 max(height[i-1],height[i+1])+1这样才能取到最小值。
上决╇ф大佬的做法就不怎么看的懂了
•将两个串用#连接,求后缀数组以及height数组
•枚举每一个前缀 ,维护这个往前和往后第一个和这个前缀的起点不在同一个串中的位置,以及第一个和这个前缀的起点在同一个串中的位置。
•定义一个函数f(i),为后缀i的一个最短前缀,满足这个字串只在该串中出现了一次,可以往前往后和本串中的后缀求最长公共前缀,然后取f(i)=max(heigth)+1
•枚举每一个后缀i,他前面第一个和他不再同一个串中的后缀j,他后面第一个和他不再同一个串中的后缀k。求出ij的最长公共前缀长度x,求出ik的最长公共前传y。根据f(i),f(j),f(k)和x,y来共同确定时候在这个位置有答案。并维护答案的最小值
我觉得上面的有第二个地方应该是后缀,,,只是我觉得啊。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int sa[N],height[N],c[N],x[N],t1[N],t2[N],n,s[N];
int dmin[N][20],rk[N];
void get_sa(int m)
{
int *x=t1,*y=t2;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void get_height()
{
for(int i=0;i<n;i++) rk[sa[i]]=i;
for(int i=0,k=0;i<n;i++)
{
if(rk[i])
{
if(k) k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
}
char str1[N],str2[N];
int vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>str1>>str2; n=0;
int l1=strlen(str1);
for(int i=0;i<l1;i++) {
s[n++]=str1[i]-'a'+1;
vis[n-1]=1;
}
s[n++]=30;
int l2=strlen(str2);
for(int i=0;i<l2;i++) {
s[n++]=str2[i]-'a'+1;
vis[n-1]=2;
}
s[n++]=0;
get_sa(31);
get_height();
int ans=N;
for(int i=1;i<=n;i++)
{
if(vis[sa[i]]+vis[sa[i-1]]==3)
{
if(height[i-1]<height[i]&&height[i+1]<height[i])
ans=min(ans,max(height[i-1],height[i+1])+1);
}
}
if(ans==N) ans=-1;
cout<<ans<<endl;
return 0;
}
上决大佬的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int sa[N],height[N],c[N],x[N],t1[N],t2[N],n,s[N];
int dmin[N][20],rk[N];
void get_sa(int m)
{
int *x=t1,*y=t2;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
void get_height()
{
for(int i=0;i<n;i++) rk[sa[i]]=i;
for(int i=0,k=0;i<n;i++)
{
if(rk[i])
{
if(k) k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
}
void initMin()
{
for(int i=1;i<=n;i++)
dmin[i][0]=height[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
}
int RMQ(int L,int R)
{
int k=0;
while(1<<(k+1)<=R-L+1) k++;
return min(dmin[L][k],dmin[R-(1<<k)+1][k]);
}
int LCP(int i,int j)
{
int L=rk[i],R=rk[j];
if(L>R) swap(L,R);
L++;
return RMQ(L,R);
}
int nxt[N][2],pre[N][2];
int super;
int getT(int pos)
{
if(pos==0||pos==n-1||sa[pos]==super)
return 2;
pos=sa[pos];
return pos>super;
}
int getlen(int pos)
{
pos=sa[pos];
if(pos<super)
return super-pos;
return n-pos-1;
}
int getminlen(int pos)
{
int tt=getT(pos);
int prepos=nxt[pos][tt];
int nxtpos=pre[pos][tt];
int maxlen=getlen(pos);
int minlen=0;
if(prepos!=0) minlen=max(minlen,LCP(sa[prepos],sa[pos]));
if(nxtpos!=n-1) minlen=max(minlen,LCP(sa[pos],sa[nxtpos]));
minlen++;
if(minlen>maxlen) return -1;
return minlen;
}
char str1[N],str2[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>str1>>str2; n=0;
int l1=strlen(str1);
for(int i=0;i<l1;i++) s[n++]=str1[i]-'a'+1;
s[n++]=30;
int l2=strlen(str2);
for(int i=0;i<l2;i++) s[n++]=str2[i]-'a'+1;
s[n++]=0;
get_sa(31);
get_height();
initMin();
super=l1;
int last[2]={0};
for(int i=0;i<n;i++)
{
pre[i][0]=last[0];
pre[i][1]=last[1];
int t=getT(i);
if(t!=2) last[t]=i;
}
last[0]=last[1]=n-1;
for(int i=n-1;i>=0;i--)
{
nxt[i][0]=last[0];
nxt[i][1]=last[1];
int t=getT(i);
if(t!=2) last[t]=i;
}
int ans=N;
for(int i=1;i<n;i++)
{
int t=getT(i);
if(t==2) continue;
int t_pos=pre[i][t^1];
///cout<<i<<" "<<t_pos<<endl;
if(t_pos==0) continue;
int t_minlen=getminlen(t_pos);
if(t_minlen==-1) continue;
int c_minlen=getminlen(i);
if(c_minlen==-1) continue;
///cout<<i<<" "<<t_pos<<endl;
int max_len=LCP(sa[i],sa[t_pos]);
int min_len=max(t_minlen,c_minlen);
///cout<<min_len<<" "<<max_len<<endl;
if(min_len>max_len) continue;
ans=min(ans,min_len);
}
if(ans==N) cout<<"-1"<<endl;
else cout<<ans<<endl;
return 0;
}