zoukankan      html  css  js  c++  java
  • SPOJ DISUBSTR Distinct Substrings 后缀数组

    题意:统计母串中包含多少不同的子串

    然后这是09年论文《后缀数组——处理字符串的有力工具》中有介绍

    公式如下:

    原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <string>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <set>
    #include <map>
    #include <utility>
    #include <vector>
    using namespace std;
    typedef long long LL;
    const int N = 1e3+5;
    int cmp(int *r,int a,int b,int l){
        return (r[a]==r[b]) && (r[a+l]==r[b+l]);
    }
    // ???????????????,
    // ????????,??????,r[n]=0(??????????)
    int wa[N],wb[N],ww[N],wv[N];
    int ran[N],height[N];
    void DA(int *r,int *sa,int n,int m){ //??N????N??1????????????????CMP???
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++) ww[i]=0;
        for(i=0;i<n;i++) ww[x[i]=r[i]]++;
        for(i=1;i<m;i++) ww[i]+=ww[i-1];
        for(i=n-1;i>=0;i--) sa[--ww[x[i]]]=i; //??????1
        for(j=1,p=1;p<n;j*=2,m=p) //?????????J?SA???2*J?SA
        {
            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; //????J??????????
            for(i=0;i<n;i++) wv[i]=x[y[i]];
            for(i=0;i<m;i++) ww[i]=0;
            for(i=0;i<n;i++) ww[wv[i]]++;
            for(i=1;i<m;i++) ww[i]+=ww[i-1];
            for(i=n-1;i>=0;i--) sa[--ww[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++;  //??????x[],???????
        }
    }
    void calheight(int *r,int *sa,int n){ // ??N?????
        int i,j,k=0;        // height[]?????? 1-N, ??0????????
        for(i=1;i<=n;i++) ran[sa[i]]=i;  // ??SA?RANK
        for(i=0;i<n; height[ran[i++]] = k ) // ???h[i] = height[ rank[i] ]
        for(k?k--:0,j=sa[ran[i]-1]; r[i+k]==r[j+k]; k++); //?? h[i] >= h[i-1]-1 ?????height??
    }
    char s[N];
    int sa[N],n,r[N],T;
    int main(){
        scanf("%d",&T);
        while(T--){
          scanf("%s",s);
          n=strlen(s);
          for(int i=0;i<n;++i)r[i]=(int)s[i];
          r[n]=0;
          DA(r,sa,n+1,128);
          calheight(r,sa,n);
          int ans = 0;
          for(int i=1;i<=n;++i)
            ans+=n-sa[i]-height[i];
          printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    遍历Map的四种方法
    过滤器和拦截器的区别
    拦截器、过滤器做什么的?
    Linux中常用操作命令
    什么是反射?
    得到字节码的方式有哪三种?
    web考试内容1
    spring注入方式
    PHP基础 第三天
    堆和栈,值传递和地址传递(引用传递)
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5718298.html
Copyright © 2011-2022 走看看