码迷,mamicode.com
首页 > 编程语言 > 详细

SPOJ705 Distinct Substrings (后缀自动机&后缀数组)

时间:2017-12-10 11:17:03      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:scan   scanf   nta   add   max   ota   case   using   bsp   

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.

Example

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.

题意:

求出大写的字符串里不同的子串。默写了一遍后缀自动机。今天主要是练习后缀数组。

 注意:

  • 注意是大写还是小写;
  • 注意init初始化的时候没有一次性memset,所以下面要把每个新出现的点memset。不要搞忘。

后缀自动机:

技术分享图片
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10000;
struct SAM
{
    int ch[maxn][26],fa[maxn],maxlen[maxn],Last,sz;
    void init()
    {
        sz=Last=1;    fa[1]=maxlen[1]=0;
        memset(ch[1],0,sizeof(ch[1]));
    }
    void add(int x)
    {
        int np=++sz,p=Last;Last=np;
        memset(ch[np],0,sizeof(ch[np]));
        maxlen[np]=maxlen[p]+1;
        while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
        if(!p) fa[np]=1;
        else {
            int q=ch[p][x];
            if(maxlen[p]+1==maxlen[q]) fa[np]=q;
            else {
                int nq=++sz;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                maxlen[nq]=maxlen[p]+1;
                fa[nq]=fa[q];
                fa[q]=fa[np]=nq;
                while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
            }
        }
    }
};
SAM Sam;
int main()
{
    char chr[maxn];
    int T,ans,i,L;
    scanf("%d",&T);
    while(T--){
        Sam.init();ans=0;
        scanf("%s",chr);
        L=strlen(chr);
        for(i=0;i<L;i++) Sam.add(chr[i]-A);
        for(i=1;i<=Sam.sz;i++) ans+=Sam.maxlen[i]-Sam.maxlen[Sam.fa[i]];
        printf("%d\n",ans);
    }
    return 0;
} 
View Code

后缀数组:

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=10000;
char ch[maxn];
int L;
struct SA
{
    int cntA[maxn],cntB[maxn],A[maxn],B[maxn];
    int rank[maxn],sa[maxn],tsa[maxn],ht[maxn];void sort()
    {
         for (int i = 0; i < 256; i ++) cntA[i] = 0;
         for (int i = 1; i <= L; i ++) cntA[ch[i]] ++;
         for (int i = 1; i < 256; i ++) cntA[i] += cntA[i - 1];
         for (int i = L; i; i --) sa[cntA[ch[i]] --] = i;
         rank[sa[1]] = 1;
         for (int i = 2; i <= L; i ++){
              rank[sa[i]] = rank[sa[i - 1]];
              if (ch[sa[i]] != ch[sa[i - 1]]) rank[sa[i]] ++;
         }
         for (int l = 1; rank[sa[L]] < L; l <<= 1){
              for (int i = 0; i <= L; i ++) cntA[i] = 0;
              for (int i = 0; i <= L; i ++) cntB[i] = 0;
              for ( int i = 1; i <= L; i ++){
                  cntA[A[i] = rank[i]] ++; 
                  cntB[B[i] = (i + l <= L) ? rank[i + l] : 0] ++;
              }
              for (int i = 1; i <= L; i ++) cntB[i] += cntB[i - 1];
              for (int i = L; i; i --) tsa[cntB[B[i]] --] = i;
              for (int i = 1; i <= L; i ++) cntA[i] += cntA[i - 1];
              for (int i = L; i; i --) sa[cntA[A[tsa[i]]] --] = tsa[i];
              rank[sa[1]] = 1;
              for (int i = 2; i <= L; i ++){
                   rank[sa[i]] = rank[sa[i - 1]];
                   if (A[sa[i]] != A[sa[i - 1]] || B[sa[i]] != B[sa[i - 1]]) rank[sa[i]] ++;
              }
         }
    }
    void getheight()
    {
         for (int i = 1, j = 0; i <= L; i ++){
              if (j) j --;
              while (ch[i + j] == ch[sa[rank[i] - 1] + j]) j ++;
              ht[rank[i]] = j;
        }
    }
};
SA Sa;
int main()
{
    int T,ans,i;
    scanf("%d",&T);
    while(T--){
        ans=0;
        scanf("%s",ch+1);
        L=strlen(ch+1);
        Sa.sort();
        Sa.getheight();
        for(i=1;i<=L;i++) ans+=L-Sa.sa[i]+1-Sa.ht[i];
        printf("%d\n",ans);
    }
    return 0;
} 

 

SPOJ705 Distinct Substrings (后缀自动机&后缀数组)

标签:scan   scanf   nta   add   max   ota   case   using   bsp   

原文地址:http://www.cnblogs.com/hua-dong/p/8016222.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!