zoukankan      html  css  js  c++  java
  • poj3261(后缀树组)

    Milk Patterns

    题意:

      求给出的串中最少出现k次的最长可重复子串的长度。

    分析:

      既然要求长度,我们就二分这个长度,判断在这个长度下是否成立。首先根据给出的串求出height数组,根据height数组的性质,如果在len长度下,存在一个区间的数都大于等于len,且区间的长度大于等于k-1(因为k-1个height代表k个后缀),那么len就是一个可重复子串的长度,二分取最优解即可。

    代码:

    #include <map>
    #include <queue>
    #include <math.h>
    #include <string>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=1e6+100;
    
    int n,k;
    
    int r[maxn],sa[maxn],Rank[maxn],height[maxn];
    
    namespace Suffix {
        int wa[maxn],wb[maxn],wv[maxn],wt[maxn];
        int cmp(int *r,int a,int b,int k)
        {
            return r[a]==r[b]&&r[a+k]==r[b+k];
        }
        void da(int *r,int *sa,int n,int m)
        {
            int i,j,p,*x=wa,*y=wb,*t;
            for(i=0; i<m; i++)  wt[i]=0;
            for(i=0; i<=n; i++)  wt[x[i]=r[i]]++;
            for(i=1; i<m; i++)  wt[i]+=wt[i-1];
            for(i=n; i>=0; i--)  sa[--wt[x[i]]]=i;
            p=1;
            j=1;
            for(; p<=n; j*=2,m=p)
            {
                for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
                for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
                for(i=0; i<=n; i++)  wv[i]=x[y[i]];
                for(i=0; i<m; i++)  wt[i]=0;
                for(i=0; i<=n; i++)  wt[wv[i]]++;
                for(i=1; i<m; i++)  wt[i]+=wt[i-1];
                for(i=n; i>=0; i--)  sa[--wt[wv[i]]]=y[i];
                t=x;
                x=y;
                y=t;
                x[sa[0]]=0;
                for(p=1,i=1; i<=n; i++)
                    x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
            }
        }
        void getheight(int *r,int* sa,int n)
        {
            int i,j,k=0;
            for(i=1; i<=n; i++)  Rank[sa[i]]=i;
            for(i=0; i<n; i++)
            {
                if(k)
                    k--;
                else
                    k=0;
                j=sa[Rank[i]-1];
                while(r[i+k]==r[j+k])
                    k++;
                height[Rank[i]-1]=k;
            }
        }
    };
    
    bool check(int x)
    {
        int cnt=0;
        for(int i=1;i<n;i++){
            if(height[i]>=x)    cnt++;
            else                cnt=0;
            if(cnt==k-1)  return true;
        }
        return false;
    }
    
    int binary_Search()
    {
        int l=1,r=n;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(mid))  l=mid+1;
            else            r=mid-1;
        }
        return r;
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        while(scanf("%d %d",&n,&k)!=EOF)
        {
            int mx=-1;
            for(int i=0;i<n;i++){
                scanf("%d",&r[i]);
                mx=max(mx,r[i]);
            }
            r[n]=0;
    
            Suffix::da(r,sa,n,mx+1);
            Suffix::getheight(r,sa,n);
    
            printf("%d
    ",binary_Search());
        }
        return 0;
    }
    View Code
  • 相关阅读:
    PAT 1010. 一元多项式求导 (25)
    PAT 1009. 说反话 (20) JAVA
    PAT 1009. 说反话 (20)
    PAT 1007. 素数对猜想 (20)
    POJ 2752 Seek the Name, Seek the Fame KMP
    POJ 2406 Power Strings KMP
    ZOJ3811 Untrusted Patrol
    Codeforces Round #265 (Div. 2) 题解
    Topcoder SRM632 DIV2 解题报告
    Topcoder SRM631 DIV2 解题报告
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9458511.html
Copyright © 2011-2022 走看看