zoukankan      html  css  js  c++  java
  • BZOJ 3796: Mushroom追妹纸

    Description

    求一个最长的串,使得他是(s_1,s_2)的子串,但(s_3)不是他的子串。

    Solution

    后缀数组+二分答案+KMP.

    单调性显然...首先可以二分一个答案,然后判断。

    判断方法就是取出(height)一段大于等于(mid)的区间,然后看看中间有没有(s_3)出现,这个可以用KMP预处理出(s_3)的匹配结尾位置来做到(O(n))查询。

    因为最多会匹配(O(frac{n}{mid}))次,所以判断复杂度为(O(n))

    总复杂度(O(nlogn))

    Code

    /**************************************************************
        Problem: 3796
        User: BeiYu
        Language: C++
        Result: Accepted
        Time:532 ms
        Memory:5300 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
     
    const int N = 100050;
     
    int n,m,l,r,l1,l2,l3;
    char s[N];
    int a[N],b[N];
     
    namespace SA {
        int t1[N],t2[N],c[N],sa[N],rk[N],ht[N];
         
        void get_sa(int a[],int n=::n,int m=::m) {
            int *x=t1,*y=t2;
            for(int i=1;i<=m;i++) c[i]=0;
            for(int i=1;i<=n;i++) c[x[i]=a[i]]++;
            for(int i=1;i<=m;i++) c[i]+=c[i-1];
            for(int i=n;i;--i) sa[c[x[i]]--]=i;
            for(int k=1,p=0;k<n;k<<=1,p=0) {
                for(int i=n-k+1;i<=n;i++) y[++p]=i;
                for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
                for(int i=1;i<=m;i++) c[i]=0;
                for(int i=1;i<=n;i++) c[x[i]]++;
                for(int i=1;i<=m;i++) c[i]+=c[i-1];
                for(int i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
                swap(x,y),x[sa[1]]=p=1;
                for(int i=2;i<=n;i++) 
                    x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p:++p;
                if(p>=n) break;m=p;
            }
        }
        void get_ht(int a[],int n=::n) {
            for(int i=1;i<=n;i++) rk[sa[i]]=i;
            for(int i=1,j,k=0;i<=n;ht[rk[i++]]=k) 
                for(j=sa[rk[i]-1],k=k?k-1:k;a[i+k]==a[j+k];k++);
        }
    }
     
    namespace KMP {
        int f[N],p[N];
        void get_f(int a[],int n=::n) {
            for(int i=2,j=0;i<=n;i++) {
                while(j && a[i]!=a[j+1]) j=f[j];
                if(a[i]==a[j+1]) j++;
                f[i]=j;
            }
        }
        void get_p(int a[],int b[],int n=::n,int m=::l3) {
            for(int i=1,j=0;i<=n;i++) {
                while(j && a[i]!=b[j+1]) j=f[j];
                if(a[i]==b[j+1]) j++;
                if(j==m) p[i]=1,j=f[j];
            }
        }
        int get_m(int st,int n,int m) {
            for(int i=st+m-1;i<=st+n-1;i++) if(p[i]) return 0;
            return 1;
        }
    }
     
    using namespace SA;
    using namespace KMP;
     
    int chk(int x) {
        for(int i=1,j;i<=n;i=j) {
            if(ht[i]<x) { j=i+1;continue; }
            int f1=sa[i-1]<=l1,f2=sa[i-1]>l1;
            for(j=i;j<=n && ht[j]>=x;f1|=(sa[j]<=l1),f2|=(sa[j]>l1),j++);
            if(f1 && f2 && get_m(sa[i],x,l3)) return 1;
        }return 0;
    }
     
    int main() {
        scanf("%s",s+1);
        l1=n=strlen(s+1);
        for(int i=1;i<=n;i++) a[i]=s[i]-'a'+1;
        a[++n]=27;
        scanf("%s",s+1);
        l2=l=strlen(s+1);
        for(int i=1;i<=l;i++) a[++n]=s[i]-'a'+1;
        get_sa(a,n,28);
        get_ht(a,n);
         
        scanf("%s",s+1);
        l3=l=strlen(s+1);
        for(int i=1;i<=l;i++) b[i]=s[i]-'a'+1;
         
        get_f(b,l3);
        get_p(a,b);
         
        l=0,r=n;
        for(;l<=r;) {
            int mm=(l+r)>>1;
            if(chk(mm)) l=mm+1;
            else r=mm-1;
        }printf("%d
    ",r);
        return 0;
    }
    

      

  • 相关阅读:
    面试题(三)
    面试题(二)
    经典面试题(一)
    $.ajax()实现简单计算器
    [hdu5373 The shortest problem]模拟
    [hdu5371 Hotaru's problem]最大回文半径
    [hdu5372 Segment Game]树状数组
    [zoj3813]Alternating Sum 公式化简,线段树
    [hdu5348]图上找环,删环
    [hdu5360]贪心
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6649586.html
Copyright © 2011-2022 走看看