题目链接:
2217 Secretary
思路:
将两个字符串用一个不会出现的字符,如$
连接起来,然后求此字符串的高度数组,从前往后遍历所有i
,当sa[i]
和sa[i+1
即两个子串的起始位置在两个不同的字符串中时(即我们相加的这两个字符串),此时i
的height
即为公共子串长度,我们找到最大值即可
代码:
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e4+99;
string s,a,b;
int n,k,sa[maxn],rk[maxn],tmp[maxn],lcp[maxn];
bool cmp(const int& i,const int& j){
if(rk[i]!=rk[j]) return rk[i]<rk[j];
else{
int ri=i+k<=n?rk[i+k]:-1;
int rj=j+k<=n?rk[j+k]:-1;
return ri<rj;
}
}
void cal_sa(){
n=s.length();
for(int i=0;i<=n;i++) sa[i]=i,rk[i]=s[i]; rk[n]=0;
for(k=1;k<=n;k<<=1){
sort(sa,sa+n+1,cmp);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++){
tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;i++) rk[i]=tmp[i];
}
}
void cal_lcp(){
for(int i=0;i<=n;i++) rk[sa[i]]=i;
int h=0; lcp[0]=0;
for(int i=0;i<n;i++){
int j=sa[rk[i]-1];
if(h) --h;
while(j+h<n&&i+h<n&&s[j+h]==s[i+h]) h++;
lcp[rk[i]-1]=h;
}
}
void solve(){
s=a+'$'+b; cal_sa(); cal_lcp();
int ans=0,len=a.length();
for(int i=0;i<s.length();i++){
if((sa[i]<len)!=(sa[i+1]<len)) ans=max(ans,lcp[i]);
}
cout<<"Nejdelsi spolecny retezec ma delku "<<ans<<".
";
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
int kase; cin>>kase; getline(cin,s);
while(kase--){
getline(cin,a); getline(cin,b);
solve();
}
return 0;
}