hdu3518---Boring counting(后缀数组,对后缀分组)

Problem Description

035 now faced a tough problem,his english teacher gives him a string,which consists with n lower case letter,he must figure out how many substrings appear at least twice,moreover,such apearances can not overlap each other.

Take aaaa as an example.”a” apears four times,”aa” apears two times without overlaping.however,aaa can’t apear more than one time without overlaping.since we can get “aaa” from [0-2](The position of string begins with 0) and [1-3]. But the interval [0-2] and [1-3] overlaps each other.So “aaa” can not take into account.Therefore,the answer is 2(“a”,and “aa”).

Input

The input data consist with several test cases.The input ends with a line “#”.each test case contain a string consists with lower letter,the length n won’t exceed 1000(n <= 1000).

Output

For each test case output an integer ans,which represent the answer for the test case.you’d better use int64 to avoid unnecessary trouble.

Sample Input

aaaa

ababcabb

aaaaaa

#

Sample Output

2

3

3

Source

2010 ACM-ICPC Multi-University Training Contest(9)——Host by HNU

Recommend

求出字符串的后缀数组,枚举长度,然后对后缀分组,由于每一组的后缀它们的排名连续,因此它们拥有相同的一段前缀,这样就不会产生重复计数问题,注意记录每一组后缀里,出现的最靠前的和最靠后的后缀位置,差不多1000*500的复杂度

/*************************************************************************
    > File Name: HDU3518.cpp
    > Author: ALex
    > Mail: [email protected]
    > Created Time: 2015年04月09日 星期四 13时35分42秒
 ************************************************************************/

#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 = 1200;
        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 / 2; ++i)
            {
                int il = sa[1], ir = sa[1];
                for (int j = 1; j < size; ++j)
                {
                    if (height[j] >= i)
                    {
                        il = min(il, sa[j + 1]);
                        ir = max(ir, sa[j + 1]);
                    }
                    else
                    {
                        if (ir - il >= i)
                        {
                            ++ans;
                        }
                        ir = il = sa[j + 1];
                    }
                }
                if (ir - il >= i)
                {
                    ++ans;
                }
            }
            printf("%d\n", ans);
        }
}SA;

char str[1200];

int main()
{
    while (~scanf("%s", str))
    {
        if (str[0] == ‘#‘)
        {
            break;
        }
        SA.clear();
        int len = strlen(str);
        for (int i = 0; i < len; ++i)
        {
            SA.insert(str[i] - ‘a‘ + 1);
        }
        SA.getsa(30);
        SA.getheight();
        SA.solve();
    }
    return 0;
}
时间: 2024-10-19 15:14:15

hdu3518---Boring counting(后缀数组,对后缀分组)的相关文章

poj 2774 最长公共子串--字符串hash或者后缀数组或者后缀自动机

http://poj.org/problem?id=2774 想用后缀数组的看这里:http://blog.csdn.net/u011026968/article/details/22801015 本文主要讲下怎么hash去找 开始的时候写的是O(n^2 logn)算法 果断超时...虽然也用了二分的,, 代码如下: //hash+二分 #include <cstdio> #include <cstring> #include <algorithm> #include

利用后缀数组构造后缀树

由于蒟蒻azui前段时间忙着准备省选,并在省选中闷声滚大粗,博客停更了好久.. 省选过后整个人各种颓,整天玩玩泥巴什么的... 前段时间学后缀数组的时候上网查相关资料,看到说后缀数组和后缀树是可以相互转化的,并且uoj上有大量通过后缀自动机建出后缀树然后dfs遍历获得后缀数组的模板,但是通过后缀数组来建后缀树的资料确实稀缺. 也许大牛们都觉得这xjbYY一下就可以写了,所以网上没找到对应的代码,那么我来补个坑吧.大牛勿喷.. 先谈谈我的理解吧.. 讲道理后缀数组和后缀树应该是完全等价的,但前两者

[TJOI2015]弦论(后缀数组or后缀自动机)

解法一:后缀数组 听说后缀数组解第k小本质不同的子串是一个经典问题. 把后缀排好序后第i个串的本质不同的串的贡献就是\(n-sa[i]+1-LCP(i,i-1)\)然后我们累加这个贡献,看到哪一个串的时候,这个贡献的和大于等于k,然后答案就在这个串里了,然后枚举就行了. 那么第k小子串该怎么办? 我们考虑二分答案,我们按字典序大小二分一个子串(具体就是二分第k小的本质不同子串,因为这个串可以\(O(n)\)求),然后看看比这个串小的串有多少个?然后改变上下界就行了. 那么我们如何求出比一个串小的

Boring counting HDU - 3518 (后缀数组)

Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要求子串之间不可以重合. 思路 对字符串后缀数组,然后枚举子串长度 \(len\),若某一段连续的 \(sa[i]\) 的 \(lcp \geq len\),那么说明这一段内存在一个长度为 \(lcp\) 的子串,而我们只需要其中的前 \(len\) 部分,接下来只要找出这个子串出现的最左和最右位置,

HDU3518 Boring counting

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3182    Accepted Submission(s): 1319 Problem Description 035 now faced a tough problem,his english teacher gives him a string,which consists with

poj 2774 最长公共子--弦hash或后缀数组或后缀自己主动机

http://poj.org/problem?id=2774 我想看看这里的后缀数组:http://blog.csdn.net/u011026968/article/details/22801015 本文主要讲下怎么hash去找 開始的时候写的是O(n^2 logn)算法 果断超时. ..尽管也用了二分的.. 代码例如以下: //hash+二分 #include <cstdio> #include <cstring> #include <algorithm> #incl

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

[HDU3518]Boring counting(后缀数组)

传送门 求出现超过1次的不重叠子串的个数 根据论文中的方法. 枚举子串的长度 k. 用 k 给 height 数组分组,每一组求解,看看当前组的位置最靠后的后缀和位置最靠前的后缀所差个数是否大于长度,大于的话 ans++. 分组思想需要认真体会一下. ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 1005 5 #define max(x, y) ((x) &

hdu3518 Boring Counting[后缀排序]

裸的统计不同的重复出现子串(不重叠)种数的题.多次使用后缀排序要注意小细节.y数组在重复使用时一定要清空,看那个line25 +k就明白了 ,cnt也要清空,为什么就不说了 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 5 temp

poj2774 Long Long Message(后缀数组or后缀自动机)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes t