SPOJ705 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.

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;
} 

后缀数组:

#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;
} 
时间: 2024-11-07 07:24:11

SPOJ705 Distinct Substrings (后缀自动机&后缀数组)的相关文章

SPOJ694&amp;&amp;SPOJ705:Distinct Substrings(后缀数组)

Description 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 numb

Spoj-DISUBSTR - Distinct Substrings~New Distinct Substrings SPOJ - SUBST1~(后缀数组求解子串个数)

Spoj-DISUBSTR - Distinct Substrings New Distinct Substrings SPOJ - SUBST1 我是根据kuangbin的后缀数组专题来的 这两题题意一样求解字符串中不同字串的个数: 这个属于后缀数组最基本的应用 给定一个字符串,求不相同的子串的个数. 算法分析: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数. 如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]), suffix(sa

POJ2774 后缀自动机&amp;后缀数组

http://poj.org/problem?id=2774 题目大意就是给两个字符串,求最长公共子串.好像可以哈希切掉,但是为了练一练后缀数组以及学一学后缀自动机,我用不同方法终于A掉了这道题. 后缀数组:就是求出height数组然后扫一遍,求出满足条件的最大值(满足条件是指height所指的两个后缀要没有公共部分),是后缀数组的水题 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 usin

康复计划#1 再探后缀自动机&amp;后缀树

本篇口胡写给我自己这样的东西都忘光的残废选手 以及那些刚学SAM,看了其他的一些东西并且没有完全懵逼的人 (初学者还是先去看有图的教程吧,虽然我的口胡没那么好懂,但是我觉得一些细节还是讲清楚了的) 大概是重复一些有用的想法和性质,用以加深印象吧-如果可以的话希望也能理解得更透彻一点- 1.如何设计出一个后缀自动机? 现在用的SAM并不是本来就在那里的,要比较深入地理解,就不能只从验证它对不对的角度考虑,而要考虑为什么它是这个样子. 要一个能够接受后缀的有限状态机,并不用像现在的SAM那样弄,比如

后缀自动机/后缀树

只是笔记罢了,不要看 关于DAWG: 见紫书P390 把后缀自动机上所有节点都设为接受态就形成DAWG,可以接受一个字符串的所有子串. 一个子串的end-set是它在原串w中出现位置(从1开始编号)的右端点集合. 在DAWG中,end-set相同的子串属于同一个状态. 原因没原因,这应该算定义吧? 任意两个节点的end-set要么不相交,要么是包含关系. 原因:在DAWG上走一步,当前end-set的变化是将原end-set中各个元素+1(要去掉超出字符串长度的元素),然后拆分成1个或多个新en

BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机 后缀自动机 字符串

https://www.lydsy.com/JudgeOnline/problem.php?id=3926 广义后缀自动机是一种可以处理好多字符串的一种数据结构(不像后缀自动机只有处理一到两种的时候比较方便). 后缀自动机可以说是一种存子串的缩小点数的trie树,广义后缀自动机就是更改了一下塞点的方式让它可以塞多个子串. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<

Distinct Substrings SPOJ - DISUBSTR(后缀数组水题)

求不重复的子串个数 用所有的减去height就好了 推出来的... #include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <cctype> #include <set> #include <vector> #include <stack> #include

后缀自动机(SAM)学习指南

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.

后缀自动机(SAM)

*在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符串所有后缀的自动机. 它最早在陈立杰的 2012 年 noi 冬令营讲稿中提到. 在2013年的一场多校联合训练中,陈立杰出的 hdu 4622 可以用 SAM 轻松水过,由此 SAM 流行了起来. 一般来说,能用后缀自动机解决的问题都可以用后缀数组解决.但是后缀自动机也拥有自己的优点. 1812.