uva12206 后缀数组

这题说的是给了一串字符 我们要将这个字符 中找出至少出现m次的最长字符串 一个字符课多次使用

利用后缀数组计算最长的lcp 

这里有一个点 记得将后缀数组中加入一个空串 如果遇到全部相同的字符时 没办法 判断 倒数第二个和 第三个的大小 因此他们就会被遗漏 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
const int maxn =100005;
struct SuffixArray
{
     int s[maxn];
     int sa[maxn];
     int t[maxn],t2[maxn],c[maxn];
     int rank[maxn],lcp[maxn];
     int n;
     void build(int m)
     {

         int *x=t,*y=t2,i;
         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)
            {
                int p=0;
                 for(i=n-k; i<n; 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];
                 for(i=0; i<n; i++)rank[ sa[i] ]=i;
                 p=1;
                 swap(x,y);
                  x[ sa[0] ] =0;
                 for(int i=1; i<n; i++)
                    x[ sa[i]  ]= y[ sa[i] ]==y[ sa[i-1] ]&&y[ sa[i]+k ]==y[ sa[i-1]+k  ] ?p-1:p++;
                 if(p>=n)break;
                 m=p;
            }
     }
     void getLcp()
     {
          int i,k=0;
          for(i=0; i<n; i++)rank[ sa[ i ] ] =i;
          for(i=0; i<n; i++)
            {
                if(k)k--;
                int j=sa[ rank[i]-1  ];
                while(s[j+k]==s[i+k])k++;
                lcp[ rank[i]  ]=k;
            }
     }
}sa;
bool solve(int len,int m)
{
     int L=0;
     for(int R=1; R<=sa.n; R++)
     {
         if(sa.lcp[R]<len||R==sa.n)
            {
                if( R-L >= m )return true;
                L=R;
            }

     }
     return false;
}
int look(int L, int R)
{
      int ans=-1;
      for(int i=L; i<R; i++)
        {
             ans=max(sa.sa[i],ans);
        }
      return ans;
}

int select(int len, int m)
{
     int L=0,ad=-1;

     for(int R=1; R<=sa.n; R++)
     {
         if(sa.lcp[R]<len||R==sa.n)
            {
                if(R-L>=m)
                    {
                        ad=max(look(L,R),ad);
                    }

                   L=R;
            }

     }
     return ad;
}
char ss[maxn];
int main()
{
    int m;
    while(scanf("%d",&m)==1)
    {

         if(m==0)break;
        scanf("%s",ss);

        sa.n=strlen(ss);
        for(int i=0; i<sa.n; i++)
            {
                 sa.s[i]= ss[i]-'a'+1;
            }
        if(m==1)
            {
               printf("%d %d
",sa.n,0); continue;
            }
        sa.s[sa.n]=0;
        sa.n++;
        sa.build(27);
        sa.getLcp();

        if(solve(1,m)==false)
            {
                puts("none");continue;
            }
        int L=1,R=sa.n,ans;
        while(L<=R)
            {
               int mid=(R+L)/2;
                if(solve(mid,m)){
                    ans=mid; L=mid+1;
                }else R=mid-1;
            }
        printf("%d %d
",ans,select(ans,m));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Opaser/p/4504500.html