SPOJ694--- DISUBSTR - 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.

求不同子串个数,每一个子串都是字符串的后缀的前缀,从suffix(sa[0])开始,每次加入一个新的后缀,子串个数加了n - sa[i] + 1个,其中height[i]个是与之前那个后缀的LCP,是重复的,需要去掉

所以加了n - sa[i] + 1 - height[i]个

/*************************************************************************
    > File Name: SPOJ694.cpp
    > Author: ALex
    > Mail: [email protected]
    > Created Time: 2015年03月31日 星期二 18时27分46秒
 ************************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>

using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

class SuffixArray
{
    public:
        static const int N = 1010;
        int init[N];
        int X[N];
        int Y[N];
        int Rank[N];
        int sa[N];
        int height[N];
        int buc[N];
        int size;

        void clear()
        {
            size = 0;
        }

        void insert(int n)
        {
            init[size++] = n;
        }

        bool cmp(int *r, int a, int b, int l)
        {
            return (r[a] == r[b] && r[a + l] == r[b + l]);
        }

        void getsa(int m = 256)
        {
            init[size] = 0;
            int l, p, *x = X, *y = Y, n = size + 1;
            for (int i = 0; i < m; ++i)
            {
                buc[i] = 0;
            }
            for (int i = 0; i < n; ++i)
            {
                ++buc[x[i] = init[i]];
            }
            for (int i = 1; i < m; ++i)
            {
                buc[i] += buc[i - 1];
            }
            for (int i = n - 1; i >= 0; --i)
            {
                sa[--buc[x[i]]] = i;
            }
            for (l = 1, p = 1; l <= n && p < n; m = p, l *= 2)
            {
                p = 0;
                for (int i = n - l; i < n; ++i)
                {
                    y[p++] = i;
                }
                for (int i = 0; i < n; ++i)
                {
                    if (sa[i] >= l)
                    {
                        y[p++] = sa[i] - l;
                    }
                }
                for (int i = 0; i < m; ++i)
                {
                    buc[i] = 0;
                }
                for (int i = 0; i < n; ++i)
                {
                    ++buc[x[y[i]]];
                }
                for (int i = 1; i < m; ++i)
                {
                    buc[i] += buc[i - 1];
                }
                for (int i = n - 1; i >= 0; --i)
                {
                    sa[--buc[x[y[i]]]] = y[i];
                }
                int i;
                for (swap(x, y), x[sa[0]] = 0, p = 1, i = 1; i < n; ++i)
                {
                    x[sa[i]] = cmp(y, sa[i - 1], sa[i], l) ? p - 1 : p++;
                }
            }
        }

        void getheight()
        {
            int h = 0, n = size;
            for (int i = 0; i <= n; ++i)
            {
                Rank[sa[i]] = i;
            }
            height[0] = 0;
            for (int i = 0; i < n; ++i)
            {
                if (h > 0)
                {
                    --h;
                }
                int j = sa[Rank[i] - 1];
                for (; i + h < n && j + h < n && init[i + h] == init[j + h]; ++h);
                height[Rank[i] - 1] = h;
            }
        }

        void solve()
        {
            int ans = 0;
            for (int i = 1; i <= size; ++i)
            {
                ans += size - sa[i]  - height[i - 1];
            }
            printf("%d\n", ans);
        }
}SA;

char str[1010];

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%s", str);
        SA.clear();
        int len = strlen(str);
        int maxs = 0;
        for (int i = 0; i < len; ++i)
        {
            SA.insert((int)str[i]);
            maxs = max(maxs, (int)str[i]);
        }
        SA.getsa(maxs + 1);
        SA.getheight();
        SA.solve();
    }
    return 0;
}
时间: 2024-10-08 18:48:47

SPOJ694--- DISUBSTR - 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 694. Distinct Substrings,705. New Distinct Substrings(后缀数组)

题目大意:给定长度为N的字符串,求出其中不相同子串的个数. 解题思路:每一个字串一定是某个后缀的前缀,那么原问题就可以等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照suffix(sa[1]),suffix(sa[2])--suffix(sa[n])的顺序计算,我们会发现对于每个新加进来的后缀suffix(sa[k]),它将产生n-sa[k]+1个新的前缀.但是其中有leight[k]个是和前面的字符串的前缀是相同的.所以suffix(sa[k])加进来增加的不同的子串的个数为n-s

spoj Distinct Substrings 后缀数组

给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和AB height[i]=1; 表明一个长度公共,所以ABA中多出现了A这个子串,所以6-1=5: 对于ABA BA height[i]=0,所以不需要减去. 最后答案为5: #include<iostream> #include<stdio.h> #include<string

SPOJ 694 || 705 Distinct Substrings ( 后缀数组 &amp;&amp; 不同子串的个数 )

题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀中找出不同的并计数呢?思路就是所有的可能子串数 - 重复的子串数.首先我们容易得到一个长度为 len 的串的子串数为 len * ( len + 1) / 2.那如何知道重复的子串数呢?答案就是利用后缀数组去跑一遍 Height ,得到所有的最长公共前缀(LCP),这些最长公共前缀的值都存在了 He

[spoj694&amp;spoj705]New Distinct Substrings(后缀数组)

题意:求字符串中不同子串的个数. 解题关键:每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数. 1.总数减去height数组的和即可. 注意这里height中为什么不需要进行组合计数,因为,每一个height的左端点已经确定,所以只需变动右端点,总共$height[i]$种情况. 2.如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),suffix(sa[3]), …… ,suffix(sa[n])的顺序计算,不难发现,对于每一次新加进来

spoj 694 Distinct Substrings 后缀数组

题目链接 求一个字符串中不相同的子串的个数. 子串的总数是(n+1)*n/2, 减去height[i]就可以. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include

SPOJ - DISUBSTR Distinct Substrings (不相同的子串的个数)

Distinct Substrings  Time Limit: 159MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu 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

POJ 1226 Substrings (后缀数组)

题目大意: 问的是m个字符串里,都出现过的子串.子串也可以出现在这个串的逆序串中. 思路分析: 居然wa在全5个 "a" 的数据上. 二分的时候下界不能为0.. 思路大致上是把原串和逆序串全部处理出来,放入str中,然后在每个串中间加一个没有出现过的. 此处注意输入不仅仅是字母. 然后跑一遍后缀数组. 然后用标记计数就好了. #include <iostream> #include <cstdio> #include <algorithm> #inc

hdu 4029 Distinct Sub-matrix (后缀数组)

题目大意: n*m的矩阵中,有多少个子矩阵不是同的. 思路分析: 假设这题题目只是一维的求一个串中有多少个子串是不同的. 那么也就是直接扫描height,然后减去前缀. 现在变成二维,如何降低维度. 知道hash 的作用就是将一个串映射到一个数字. 那我们就将这个矩阵hash,考虑到不同的长度和宽度都会导致不同, 所以就要枚举子矩阵的宽度. hash [i][j] 就表示在当前宽度W 下,从 第 i 行 第 j 个开始往后W长度的串的hash值. 然后将列上相同起点的hash值 子串. 然后将所