美文网首页
后缀数组_可重叠的 k 次最长重复子串

后缀数组_可重叠的 k 次最长重复子串

作者: Gitfan | 来源:发表于2017-03-11 15:24 被阅读0次

    http://www.cnblogs.com/staginner/archive/2012/02/03/2337482.html

    我们可以通过二分子串的长度k来做,这时就将题目变成了是否存在重复次数至少为K次且长度不小k的字符串。首先我们可以把相邻的所有不小于k的height[]看成一组,这组内有多少个字符串,就相当于有多少个长度至少为k的重复的子串。之所以可以这么做,是因为排名第i的字符串和排名第j的字符串的最长公共前缀等于height[i],height[i+1],...,height[j]中的最小值,所以把所有不小于k的height[]看成一组就保证了组内任意两个字符串的最长公共前缀都至少为k,且长度为k的前缀是每个字符串共有的,因此这组内有多少个字符串,就相当于有多少个长度至少为k的重复的子串(任意一个子串都是某个后缀的前缀)。

    http://poj.org/problem?id=3261

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    using namespace std;
    int s[maxn];
    int sa[maxn],t[maxn],t2[maxn],c[maxn],Rank[maxn],height[maxn],n;
    void build_sa(int m){
        int i,*x=t,*y=t2,*T,p ;
        n++;
        for(i=0;i<m;++i)c[i]=0;
        for(i=0;i<n;++i)++c[x[i]=s[i]];
        for(i=1;i<m;++i)c[i]+=c[i-1];
        for(i=n-1;i>=0;--i)sa[--c[x[i]]]=i;
        for(int k=1;k<=n;k<<=1)
        {
              p=0;
           for(i=n-1;i>=n-k;--i)y[p++]=i;
           for(i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
           for(i=0;i<m;++i)c[i]=0;
           for(i=0;i<n;++i)++c[x[y[i]]];
           for(i=1;i<m;++i)c[i]+=c[i-1];
           for(i=n-1;i>=0;--i)sa[--c[x[y[i]]]]=y[i];
           swap(x,y);
           x[sa[0]]=0;p=1;
           for(i=1;i<n;++i)
             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
           if(p>=n)break;
           m=p;
        }
        n--;
       // for(int i=1;i<=n;++i)printf("%d ",sa[i]+1);
        //printf("\n");
    
    }
    void cal_height(){
        int i,j,k=0;
        for(i=1;i<=n;i++)Rank[sa[i]]=i;
        for(int i=0;i<n;++i)
        {
           j=sa[Rank[i]-1];//h[i-1]
           if(k)k--;
           while(s[i+k]==s[j+k])k++;
           height[Rank[i]]=k;//h[i]
        }
        //for(int i=2;i<=n;++i)printf("%d ",height[i]);
    }
    bool check(int k,int t)
    {
        int i,total=1;
        for(i=2;i<=n;i++)
        {
            if(height[i]<k)
            {
                total=1;
            }
            else
            {
                total++;
                if(total>=t) return true;
            }
        }
        return false;
    }
    int main(){
        int a,b,t;
        scanf("%d%d",&n,&t);
            for(int i=0;i<n;i++)
            {
                scanf("%d",&b);
                s[i]=b;
            }
            build_sa(180);
            cal_height();
            int l=1,r=n,mid;
            while(r-l>1)
            {
                mid=(l+r)/2;
                if(check(mid,t)) l=mid;
                else r=mid;
            }
            printf("%d\n",l);
    }
    

    http://poj.org/problem?id=3882

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 40010
    using namespace std;
    char s[maxn];
    int sa[maxn],t[maxn],t2[maxn],c[maxn],Rank[maxn],height[maxn],n,pos,loc;
    void build_sa(int m){
        int i,*x=t,*y=t2,*T,p ;
        n++;
        for(i=0;i<m;++i)c[i]=0;
        for(i=0;i<n;++i)++c[x[i]=s[i]];
        for(i=1;i<m;++i)c[i]+=c[i-1];
        for(i=n-1;i>=0;--i)sa[--c[x[i]]]=i;
        for(int k=1;k<=n;k<<=1)
        {
              p=0;
           for(i=n-1;i>=n-k;--i)y[p++]=i;
           for(i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
           for(i=0;i<m;++i)c[i]=0;
           for(i=0;i<n;++i)++c[x[y[i]]];
           for(i=1;i<m;++i)c[i]+=c[i-1];
           for(i=n-1;i>=0;--i)sa[--c[x[y[i]]]]=y[i];
           swap(x,y);
           x[sa[0]]=0;p=1;
           for(i=1;i<n;++i)
             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
           if(p>=n)break;
           m=p;
        }
        n--;
       // for(int i=1;i<=n;++i)printf("%d ",sa[i]+1);
        //printf("\n");
    
    }
    void cal_height(){
        int i,j,k=0;
        for(i=1;i<=n;i++)Rank[sa[i]]=i;
        for(int i=0;i<n;++i)
        {
           j=sa[Rank[i]-1];//h[i-1]
           if(k)k--;
           while(s[i+k]==s[j+k])k++;
           height[Rank[i]]=k;//h[i]
        }
        //for(int i=2;i<=n;++i)printf("%d ",height[i]);
    }
    bool check(int k,int t)
    {
        int i,total=1,p=0;
        bool flag=false;
        pos=0;
        //pos=max(sa[1],pos);
        for(i=2;i<=n;i++)
        {
            if(height[i]<k)
            {
                p=0;
                total=1;
            }
            else
            {
                total++;
                p=max(p,max(sa[i],sa[i-1]));
                if(total>=t)
                {
                    if(!flag) pos=p;
                    else pos=max(p,pos);
                    flag=true;
    
                }
    
            }
    
        }
        return flag;
    }
    int main(){
    
        int t;
        while(scanf("%d",&t),t)
        {
            scanf("%s",s);
            n=strlen(s);
            if(t==1)
           { printf("%d 0\n",n);continue;}
    
            build_sa(256);
            cal_height();
            int l=1,r=n,mid;
            loc=-1;
            while(l<=r)
            {
                mid=(l+r)/2;
                if(check(mid,t)) l=mid+1,loc=pos;
                else r=mid-1;
            }
            if(loc!=-1)
            printf("%d %d\n",l-1,loc);
            else printf("none\n");
        }
    }
    

    相关文章

      网友评论

          本文标题:后缀数组_可重叠的 k 次最长重复子串

          本文链接:https://www.haomeiwen.com/subject/tvoagttx.html