zoukankan      html  css  js  c++  java
  • Spoj 694 Distinct Substrings

    Given a string, we need to find the total number of its distinct substrings.

    给你一个字符中,统计有多少个不同的子串
    Input
    T- number of test cases. T<=20;
    Each test case consists of one string, whose length is <= 1000
    Output
    For each test case output one number saying the number of distinct substrings.
    Sample Input
    2
    CCCCC
    ABABA
    Sample Output
    5
    9
    //Explanation for the testcase with string ABABA:
    len=1 : A,B
    len=2 : AB,BA
    len=3 : ABA,BAB
    len=4 : ABAB,BABA
    len=5 : ABABA
    Thus, total number of distinct substrings is 9.

    Sol:

    某个子串一定是某个后缀的前缀, 那么原问题等价于求所有后缀之间的不相
    同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),
    suffix(sa[3]), …… ,suffix(sa[n])的顺序计算, 不难发现, 对于每一次新加
    进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀。(对于某个排名K来说,n-sa[k]+1,事实上相当于排第K的后缀,它的长度有多少,设之为Len,于是从1到Len,可以形成[1,1],[1,2],[1,3]......[1,Len]个前缀。但是其中有
    height[k]个是和前面的字符串的前缀是相同的。所以suffix(sa[k])将“ 贡献”
    出n-sa[k]+1- height[k]个不同的子串)。累加后便是原问题的答案。

    例如对于字符aabc

    排第一的是aabc,它将形成a,aa,aab,aabc四个子串

    排第二的是abc,它将形成a,ab,abc三个子串。发现a这个子串前面出现过了,于是减去之

    拓第三的是bc,它将形成b,bc二个子串。bc与前面的abc没有公共前缀,于是不用减去。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define maxn 2005
    using namespace std;
     
    char st[1001];
    int ca,n,ans,tot,tmp[maxn],rankk[maxn],sa[maxn],sum[maxn],hei[maxn];
     
    int main(){
          scanf("%d",&ca);
          while (ca--){
                    scanf("%s",st+1);
                    n=strlen(st+1);
                    memset(sum,0,sizeof(sum));
                    for (int i=1;i<=n;i++) sum[tmp[i]=st[i]]++;
                    for (int i=1;i<=256;i++) sum[i]+=sum[i-1];
                    for (int i=n;i>=1;i--) sa[sum[tmp[i]]--]=i;
                    tot=0;
                    rankk[sa[1]]=++tot;
                    for (int i=2;i<=n;i++){
                           if (tmp[sa[i]]!=tmp[sa[i-1]]) tot++;
                           rankk[sa[i]]=tot;
                    }
                    for (int len=1;len<=n;len<<=1){
                               memset(sum,0,sizeof(sum));
                               for (int i=1;i<=n;i++) sum[rankk[i+len]]++;
                               for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
                               for (int i=n;i>=1;i--) tmp[sum[rankk[i+len]]--]=i;
                               memset(sum,0,sizeof(sum));
                               for (int i=1;i<=n;i++) sum[rankk[i]]++;
                               for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
                               for (int i=n;i>=1;i--) sa[sum[rankk[tmp[i]]]--]=tmp[i];
                               tot=0;
                               tmp[sa[1]]=++tot;
                               for (int i=2;i<=n;i++){
                                       if (rankk[sa[i]]!=rankk[sa[i-1]]||rankk[sa[i]+len]!=rankk[sa[i-1]+len]) tot++;
                                       tmp[sa[i]]=tot;
                               }
                               for (int i=1;i<=n;i++) rankk[i]=tmp[i];
                    }
                    hei[1]=0;
                    for (int i=1,j=0;i<=n;i++){
                               if (rankk[i]==1) continue;
                               while (st[i+j]==st[sa[rankk[i]-1]+j]) j++;
                               hei[rankk[i]]=j;
                               if (j) j--;
                    }
                    ans=n;
                    for (int i=2;i<=n;i++){
                           ans+=(n-i+1);
                           ans-=hei[i];
                    }
                    printf("%d
    ",ans);
          }
          return 0;
    }
    

      

  • 相关阅读:
    理性与感性
    JVM系列(之class文件)
    Java集合框架
    Java字符串连接的几种方式
    JVM系列(之ClassLoader)
    时之终结
    约束中的存在
    拿什么爱你?我的数学
    梦的表征、抽象的思维
    Spider with R
  • 原文地址:https://www.cnblogs.com/cutemush/p/12336866.html
Copyright © 2011-2022 走看看