【bzoj3796】Mushroom追妹子(二分+哈希)

题意:给定字符串 s 1 , s 2 , s 3 ,求一个字符串 w ,它同时是 s 1 , s 2 的子串,且它的子串中不含有 s 3 ,求 w 的最大可能长度。
数据范围: 1 <= | s 1 | , | s 2 | <= 50000 , 1 <= | s 3 | <= 10000

哈希大法好!
首先我们预处理出 s 1 s 2 的前缀哈希值, s 3 的哈希值。
第一步是先处理出在 s 1 s 2 中找到有哪些位置是 s 3 。既然有哈希值了,为什么不直接用哈希来进行字符串匹配呢?(当然KMP也可以)我们枚举 s 1 ( s 2 ) 的每一位,然后判断以这个位置为开头,往后 | s 3 | 这一段子串的哈希值(这个可以利用前缀哈希值随便搞定)是否等于 w 的哈希值,然后就好了。
然后二分答案, O ( n l g n ) 暴力判断。具体的话请看代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/ezoiHQM/article/details/81460813