题意:给定字符串
,求一个字符串
,它同时是
的子串,且它的子串中不含有
,求
的最大可能长度。
数据范围:
哈希大法好!
首先我们预处理出
和
的前缀哈希值,
的哈希值。
第一步是先处理出在
和
中找到有哪些位置是
。既然有哈希值了,为什么不直接用哈希来进行字符串匹配呢?(当然KMP也可以)我们枚举
的每一位,然后判断以这个位置为开头,往后
这一段子串的哈希值(这个可以利用前缀哈希值随便搞定)是否等于
的哈希值,然后就好了。
然后二分答案,
暴力判断。具体的话请看代码:
#include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const unsigned long long p=133706993421;
char s1[50010],s2[50010],s3[10010];
int n,len1,len2,len3,cnt1,cnt2,end1[50010],end2[50010],ans;
unsigned long long hash1[50010],hash2[50010],hash3[10010],base[50010];
bool check(int len){
set<unsigned long long>S;
int t=0;
for(int i=len;i<=len1;i++){
while(end1[t+1]<=i&&t<cnt1)
t++;
if(!t||(i-len+1>end1[t]-len3+1))
S.insert((hash1[i]-hash1[i-len])*base[n-i]);
}
t=0;
for(int i=len;i<=len2;i++){
while(end2[t+1]<=i&&t<cnt2)
t++;
if(!t||(i-len+1>end2[t]-len3+1))
if(S.count((hash2[i]-hash2[i-len])*base[n-i]))
return 1;
}
return 0;
}
int main(){
scanf("%s%s%s",s1+1,s2+1,s3+1);
len1=strlen(s1+1);
len2=strlen(s2+1);
len3=strlen(s3+1);
n=max(len1,max(len2,len3));
base[0]=1;
for(int i=1;i<=n;i++)
base[i]=base[i-1]*p;
for(int i=1;i<=len1;i++)
hash1[i]=hash1[i-1]+(s1[i]-'a'+1)*base[i];
for(int i=1;i<=len2;i++)
hash2[i]=hash2[i-1]+(s2[i]-'a'+1)*base[i];
for(int i=1;i<=len3;i++)
hash3[i]=hash3[i-1]+(s3[i]-'a'+1)*base[i];
for(int i=len3;i<=len1;i++)
if(hash1[i]-hash1[i-len3]==hash3[len3]*base[i-len3])
end1[++cnt1]=i;
for(int i=len3;i<=len2;i++)
if(hash2[i]-hash2[i-len3]==hash3[len3]*base[i-len3])
end2[++cnt2]=i;
int l=0,r=min(len1,len2);
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d",ans);
return 0;
}