zoukankan      html  css  js  c++  java
  • BZOJ 3796 Mushroom追妹纸 哈希+二分(+KMP)

    先把两个串能匹配模式串的位置找出来,然后标记为$1$(标记在开头或末尾都行),然后对标记数组求一个前缀和,这样可以快速查到区间内是否有完整的一个模式串。

    然后二分子串(答案)的长度,每次把长度为$md$的串扔到哈希表里,查一波匹不匹配。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define ull unsigned long long
    #define ll long long
    #define R register int
    using namespace std;
    const int M=10000000,N=50010,B=131;
    namespace HASH {
        const int P=19260817;
        int fir[P],nxt[M],cnt; ull vl[M];
        inline void clear() {memset(fir,0,sizeof(fir)),memset(nxt,0,sizeof(int)*(cnt+1)),memset(vl,0,sizeof(ull)*(cnt+1)),cnt=0;}
        inline void ins(ull x) {
            R st=x%P; for(R i=fir[st];i;i=nxt[i]) if(vl[i]==x) return ;
            vl[++cnt]=x,nxt[cnt]=fir[st],fir[st]=cnt;
        }
        inline int find(ull x) {R st=x%P; for(R i=fir[st];i;i=nxt[i]) if(vl[i]==x) return 1; return 0;}
    } int l1,l2,ls,nxt[N/5],c1[N],c2[N];
    char s1[N],s2[N],s[N/5];
    ull h1[N],h2[N],p[N];
    inline void PRE() {
        for(R i=2,j=0;i<=ls;++i) {
            while(j&&(s[i]!=s[j+1])) j=nxt[j];
            if(s[i]==s[j+1]) ++j; nxt[i]=j;
        }
    }
    inline void calc() {
        for(R i=1,j=0;i<=l1;++i) {
            while(j&&(j==ls||s1[i]!=s[j+1])) j=nxt[j];
            if(s1[i]==s[j+1]) ++j; 
            if(j==ls) ++c1[i];
        } for(R i=1;i<=l1;++i) c1[i]+=c1[i-1];
        for(R i=1,j=0;i<=l2;++i) {
            while(j&&(j==ls||s2[i]!=s[j+1])) j=nxt[j];
            if(s2[i]==s[j+1]) ++j; 
            if(j==ls) ++c2[i];
        } for(R i=1;i<=l2;++i) c2[i]+=c2[i-1];
    }
    inline bool ck(int md) {
        for(R i=md;i<=l1;++i) if(md<ls||c1[i]-c1[i-md+ls-1]==0) HASH::ins(h1[i]-h1[i-md]*p[md]);
        for(R i=md;i<=l2;++i) if(md<ls||c2[i]-c2[i-md+ls-1]==0) if(HASH::find(h2[i]-h2[i-md]*p[md])) return true;
        HASH::clear(); return false;
    }
    signed main() { 
        scanf("%s%s%s",s1+1,s2+1,s+1); 
        l1=strlen(s1+1),l2=strlen(s2+1),ls=strlen(s+1); 
        PRE(),calc(); p[0]=1; for(R i=1;i<=50000;++i) p[i]=p[i-1]*B;
        for(R i=1;i<=l1;++i) h1[i]=h1[i-1]*B+s1[i];
        for(R i=1;i<=l2;++i) h2[i]=h2[i-1]*B+s2[i];
        R l=0,r=min(l1,l2)+1; while(l<r) {R md=l+r>>1; if(ck(md)) l=md+1; else r=md;}
        printf("%d
    ",l-1);
    } 

    2019.06.12

  • 相关阅读:
    Lab IGMP
    IGMP知识要点
    15、通过例子讲解逻辑地址转换为物理地址的基本过程
    14、一个程序从开始运行到结束的完整过程,你能说出来多少?
    13、进程状态的切换你知道多少?
    12、虚拟技术你了解吗?
    11、动态分区分配算法有哪几种?可以分别说说吗?
    线程池
    10、内存交换和覆盖有什么区别?
    9、如果系统中具有快表后,那么地址的转换过程变成什么样了?
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11013588.html
Copyright © 2011-2022 走看看