hdu4622-Reincarnation(后缀自动机)

Problem Description

Now you are back,and have a task to do:
Given you a
string s consist of lower-case English letters only,denote f(s) as the number of
distinct sub-string of s.
And you have some query,each time you should
calculate f(s[l...r]), s[l...r] means the sub-string of s start from l end at
r.

Input

The first line contains integer T(1<=T<=5),
denote the number of the test cases.
For each test cases,the first line
contains a string s(1 <= length of s <= 2000).
Denote the length of s
by n.
The second line contains an integer Q(1 <= Q <= 10000),denote the
number of queries.
Then Q lines follows,each lines contains two integer l,
r(1 <= l <= r <= n), denote a query.

Output

For each test cases,for each query,print the answer in
one line.

Sample Input

2

bbaba

5

3 4

2 2

2 5

2 4

1 4

baaba

5

3 3

3 4

1 4

3 5

5 5

Sample Output

3

1

7

5

8

1

3

8

5

1

题意: 给一个字符串长度最大2000,给出Q个查询[l,r]包含多少种连续的子串。
解析: 后缀自动机轻松过,先对查询离线排序,对于左端点相同的建立一个后缀自动
机,字符串长度最大只有2000,所以最后只用建2000个,每个sam插入的字符最多也就
2000,时间肯定是够的。

代码

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=4005;
struct SAM
{
    int ch[maxn][26];
    int pre[maxn],step[maxn];
    int last,id;
    void init()
    {
        last=id=0;
        memset(ch[0],-1,sizeof(ch[0]));
        pre[0]=-1; step[0]=0;
    }
    void Insert(int c) //字符转化为数
    {
        int p=last,np=++id;
        step[np]=step[p]+1;
        memset(ch[np],-1,sizeof(ch[np]));
        while(p!=-1&&ch[p][c]==-1)  ch[p][c]=np,p=pre[p];
        if(p==-1) pre[np]=0;
        else
        {
            int q=ch[p][c];
            if(step[q]!=step[p]+1)
            {
                int nq=++id;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                step[nq]=step[p]+1;
                pre[nq]=pre[q];
                pre[np]=pre[q]=nq;
                while(p!=-1&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];
            }
            else pre[np]=q;
        }
        last=np;
    }
    int GetCnt()
    {
        int ret=0;
        for(int i=id;i>=1;i--) ret+=step[i]-step[pre[i]];
        return ret;
    }
}sam;
char S[maxn/2];
struct Ques
{
    int l,r,id;
    Ques(int l=0,int r=0,int id=0):l(l),r(r),id(id){}
    bool operator < (const Ques& t) const
    {
        if(l!=t.l) return l<t.l;
        return r<t.r;
    }
}q[10005];
int Q,ans[10005];
void solve()
{
    sort(q,q+Q);
    int last;
    for(int i=0;i<Q;i++)
    {
        if(i==0||q[i].l!=q[i-1].l)
        {
            sam.init();
            last=q[i].l;
        }
        for(;last<=q[i].r;last++) sam.Insert(S[last]-‘a‘);
        ans[q[i].id]=sam.GetCnt();
    }
    for(int i=0;i<Q;i++) printf("%d\n",ans[i]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",S+1);
        int len=strlen(S);
        scanf("%d",&Q);
        int l,r,id;
        for(int i=0;i<Q;i++)
        {
            scanf("%d%d",&l,&r);
            q[i]=Ques(l,r,i);
        }
        solve();
    }
    return 0;
}

时间: 2024-10-08 13:29:03

hdu4622-Reincarnation(后缀自动机)的相关文章

HDU 4622 Reincarnation 后缀自动机

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Problem Description Now you are back,and have a task to do:Given you a string s consist of lower-case English letters only,denote f(s) as the number of

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

Problem Description Now you are back,and have a task to do: Given you a string s consist of lower-case English letters only,denote f(s) as the number of distinct sub-string of s. And you have some query,each time you should calculate f(s[l...r]), s[l

hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)

Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 2138    Accepted Submission(s): 732 Problem Description Now you are back,and have a task to do: Given you a string s consist of lo

hdu4622(后缀自动机模板)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意: 先输入一个长度为 n 的字符串, 然后有 q 个形如 l, r 的询问, 对于每个询问输出区间 [l, r] 中有多少不同的子串 思路: 后缀自动机模板 代码: 1 // 后缀自动机要理解其含义,从起点到每个点的不同路径,就是不同的子串. 2 // 到每一个点,不同路径,其实就是以这个点为最后一个字符的后缀,长度是介于(p->fa->len,p->len]之间的,个数也就清楚

HDU 4622 Reincarnation(后缀自动机)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4622 [题目大意] 给出一个长度不超过2000的字符串,有不超过10000个询问,问[L,R]子串中出现的子串数目,相同子串不可重复计数. [题解] 考虑到字符串长度只有两千,我们对每个位置往后建立2000个后缀自动机, 这样子就能分别计算每个位置往后出现的字符串数目并保存, 对于sam上的一个节点来说,它的匹配长度与失配位置的匹配长度只差就是他们之间的子串, 所以,我们在建立sam可以同时计算

HDU4622 (查询一段字符串的不同子串个数,后缀自动机)

http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给出一个字符串和q次询问,每次询问[l,r]区间内不同子串的个数 分析: N<=2000. 我是用后缀自动机预处理出所有区间的不同子串个数. 建立n次后缀自动机. 为什么要建立N次呢? 因为鸭 , 后缀自动机之所以有继承性是因为定义的起点是相同的 , 而起点不同是没有继承性的  , 所以要枚举n次不同的节点建立后缀自动机. 用一个变量t , 不断的累加建立到当前点有多少个不同的字符串 , 就是前缀

后缀自动机习题合集

(写的都是初中小朋友czl早就切过的题……) http://www.cnblogs.com/Lyush/p/3281546.html POJ-1509 Glass Beads UVA - 719 Glass Beads 题意:一个字符串可以将第一个字符放到最后一位,然后问不断这样做可以得到的字典序最小的字符串 sam模板题,copy一遍建个sam,然后直接在sam中跑一遍就行了. sam记录了字符串的所有后缀(也随便记录了字串),从root开始到每个接受态节点都是一个后缀(或多个),从root开

后缀自动机(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.

hiho一下第128周 后缀自动机二&#183;重复旋律5

#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中出现了多少不同的旋律? 解题方法提示 输入 共一行,包含一个由小写字母构成的字符串.字符串长度不超过 1000000. 输出 一行一个整数,表示答案. 样例输入 aab 样例输出 5 解题方法提示 小Hi:本周的题目其实就是给定一个字符串S,要求出S的所有不同子串的数