zoukankan      html  css  js  c++  java
  • 后缀数组小结

    后缀数组是处理字符串问题的有力工具。

    其中有些变量需要说明下,sa[i]是排名为第i的后缀所在字符串中的位置。height[i]表示sa[i-1]和sa[i]两个后缀的最长公共前缀,即相邻排名两串的公共前缀。

    LCP(i,j)也就是后缀数组中第i个和第j个后缀的最长公共前缀的长度

    例题,uva 12506,求区别所有字符串的最少字符数

    具体见代码:

    View Code
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<climits>
    using namespace std;
    
    #define maxn 1000009
    int wa[maxn],wb[maxn],wv[maxn],wsm[maxn],sa[maxn],Len[maxn],pos[maxn];
    int cmp(int *r,int a,int b,int l)
    {return r[a]==r[b]&&r[a+l]==r[b+l];}
    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++) wsm[i]=0;
        for(i=0;i<n;i++) wsm[x[i]=r[i]]++;
        for(i=1;i<m;i++) wsm[i]+=wsm[i-1];
        for(i=n-1;i>=0;i--) sa[--wsm[x[i]]]=i;
        for(j=1,p=1;p<n;j*=2,m=p)
        {
            for(p=0,i=n-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++) wsm[i]=0;
            for(i=0;i<n;i++) wsm[wv[i]]++;
            for(i=1;i<m;i++) wsm[i]+=wsm[i-1];
            for(i=n-1;i>=0;i--) sa[--wsm[wv[i]]]=y[i];
            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
        return;
    }
    int Rank[maxn],height[maxn];
    void calheight(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;height[Rank[i++]]=k)
            for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
        return;
    }
    int RMQ[maxn];
    int mm[maxn];
    int best[20][maxn];
    void initRMQ(int n)
    {
        for(int i = 0; i <= n; i++)
            RMQ[i] = height[i];
        int i,j,a,b;
        for(mm[0]=-1,i=1;i<=n;i++)
            mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
        for(i=1;i<=n;i++) best[0][i]=i;
        for(i=1;i<=mm[n];i++)
            for(j=1;j<=n+1-(1<<i);j++)
            {
                a=best[i-1][j];
                b=best[i-1][j+(1<<(i-1))];
                if(RMQ[a]<RMQ[b]) best[i][j]=a;
                else best[i][j]=b;
            }
        return;
    }
    
    int askRMQ(int a,int b)
    {
        int t;
        t=mm[b-a+1];b-=(1<<t)-1;
        a=best[t][a];b=best[t][b];
        return RMQ[a]<RMQ[b]?a:b;
    }
    int lcp(int a,int b)
    {
        int t;
        a=Rank[a];b=Rank[b];
        if(a>b) {t=a;a=b;b=t;}
        return height[askRMQ(a+1,b)];
    }
    
    char ss[maxn];
    int ans[maxn];
    
    int main(){
        int cas;
        scanf("%d",&cas);
        for(int tcase=1;tcase<=cas;tcase++){
            int n;
            scanf("%d",&n);
            int cnt = 0;
            for(int i=1;i<=n;i++){
                scanf("%s",ss);
                int len = strlen(ss);
                pos[i] = cnt;
                Len[i] = len;
                for(int j=0;j<len;j++){
                    ans[cnt++] = ss[j]-'a'+500;
                }
            }
            ans[cnt]=0;
            da(ans,sa,cnt+1,1280);
            calheight(ans,sa,cnt);
            initRMQ(cnt);
            int was = 0;
            for(int i=1;i<=n;i++){
                int ans1 = 0;
                for(int j=1;j<=n;j++){
                    if(i==j)
                        continue;
                    ans1 = max(ans1,lcp(pos[i],pos[j]));
                }
                was += ans1+1;
            }
            printf("%d\n",was);
        }
        return 0;
    }
  • 相关阅读:
    函数与递归、第五章习题
    第四章习题continue、break
    程序异常处理
    第一章习题
    第三章习题.split('')
    文本进度条
    字符串处理函数、Unicode
    字符串处理.<方法>()
    springbatch
    卸载gitlab
  • 原文地址:https://www.cnblogs.com/gray035/p/3033242.html
Copyright © 2011-2022 走看看