字符串(后缀自动机):HDU 4622 Reincarnation

Reincarnation

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 3194    Accepted Submission(s): 1184

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

Hint

I won‘t do anything against hash because I am nice.Of course this problem has a solution that don‘t rely on hash.

  程立杰出的题目?

  sam有个性质就是对于新加一个字符,产生的新子串个数为len[lst]-len[fa[lst]]。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int maxn=4010;
 6 int fa[maxn],ch[maxn][26];
 7 int len[maxn],lst,cnt;
 8 int dp[maxn][maxn];
 9 char s[maxn];
10 struct Opt{
11     void Init(){
12         memset(ch,0,sizeof(ch));
13         lst=cnt=1;
14     }
15
16     int Insert(int c){
17         int p=lst,np=lst=++cnt;len[np]=len[p]+1;
18         while(p&&ch[p][c]==0)ch[p][c]=np,p=fa[p];
19         if(!p)fa[np]=1;
20         else{
21             int q=ch[p][c];
22             if(len[q]==len[p]+1)fa[np]=q;
23             else{
24                 int nq=++cnt;len[nq]=len[p]+1;
25                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
26                 fa[nq]=fa[q];fa[q]=fa[np]=nq;
27                 while(ch[p][c]==q)ch[p][c]=nq,p=fa[p];
28             }
29         }
30         return len[lst]-len[fa[lst]];
31     }
32 }SAM;
33 int main(){
34     int T,Q;
35     scanf("%d",&T);
36     while(T--){
37         scanf("%s",s+1);
38         int len=strlen(s+1);
39         for(int i=1;i<=len;i++){
40             SAM.Init();
41             for(int j=i;j<=len;j++)
42                 dp[i][j]=dp[i][j-1]+SAM.Insert(s[j]-‘a‘);
43         }
44         scanf("%d",&Q);
45         while(Q--){
46             int l,r;
47             scanf("%d%d",&l,&r);
48             printf("%d\n",dp[l][r]);
49         }
50     }
51     return 0;
52 }
时间: 2024-10-29 19:07:45

字符串(后缀自动机):HDU 4622 Reincarnation的相关文章

HDU 4622 Reincarnation Hash解法详解

今天想学字符串hash是怎么弄的.就看到了这题模板题 http://acm.hdu.edu.cn/showproblem.php?pid=4622 刚开始当然不懂啦,然后就上网搜解法.很多都是什么后缀自动机那些.作为小白的我当然不懂啦,更重要的是我想学的是字符串hash这种解法呢?然而有这种解法,但是却都是只有代码,看起来很辛苦.所以这里我把我的理解写上来,当然有错误的话,请各路高手指出来,我也好好学习下~~ 首先介绍一个字符串Hash的优秀映射函数:BKDRHash,这里hash一开始是等于0

字符串后缀自动机:Directed Acyclic Word Graph

trie -- suffix tree -- suffix automa 有这么一些应用场景: 即时响应用户输入的AJAX搜索框时, 显示候选列表. 搜索引擎的关键字个数统计. 后缀树(Suffix Tree): 从根到叶子表示一个后缀. 仅仅从这一个简单的描述,我们可以概念上解决下面的几个问题: P:查找字符串o是否在字符串S中 A:若o在S中,则o必然是S的某个后缀的前缀. 用S构造后缀树,按在trie中搜索字串的方法搜索o即可. P: 指定字符串T在字符串S中的重复次数. A: 如果T在S

HDU 4622 Reincarnation(后缀自动机)

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

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

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

HDU 4622 Reincarnation

Reincarnation Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 462264-bit integer IO format: %I64d      Java class name: Main Now you are back,and have a task to do:Given you a string s consist of lower-case E

HDU 4622 Reincarnation( 任意区间子串的长度, 后缀数组+RMQ)

题目大意:给你一个字符串,给你N次查询,每次给你一个区间让你求出这个区间里面有多少子串. 解题思路:我们肯定要枚举位置,然后找公共子串然后再去掉重复的,但是他的地址对应的rank不是连续的,如果暴力找的话会n*n会超时. 从这个博客学习到一种方法:首先对整个字符串求一次sa[]以及height[],之后对于任意区间[L, R],遍历一遍sa[],只要起点在[L, R]内的后缀就需要进行统计,类似于1)中的方法,不过有一个地方要特别注意的就是全部的sa[]不一定就是区间内的sa[],这是因为区间内

hdu 4622 Reincarnation SAM模板题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给定一个长度不超过2000的字符串,之后有Q次区间查询(Q <= 10000),问区间中不同的子串数为多少? 学习资料: 知乎 SAM解析: 看了clj的PPT,对于最后为什么这样子插入节点还是有些不懂... 下面先讲讲一些理解 1.找出母串A中的所有子串可以看做是先找出A串的所有后缀,再在后缀中找出前缀(后缀中找前缀):其中的init(初始状态)是指可以匹配所有后缀的原始状态,即可以对

HDU 4622 Reincarnation(SAM)

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