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

Reincarnation

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

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.  

 

Source
2013 Multi-University Training Contest 3  

 

Recommend zhuyuanchen520  

 

 

 

刚刚学了下后缀自动机,然后把这题先A掉。

 

这题就是查询一个区间内的不同子串的个数。

如果单单是求一个字符串的不同子串个数,无论是后缀数组还是后缀自动机都非常容易实现。

 

N<=2000.

我是用后缀自动机预处理出所有区间的不同子串个数。

建立n次后缀自动机。

 

后缀自动机要理解其含义,从起点到每个点的不同路径,就是不同的子串。

到每一个点,不同路径,其实就是以这个点为最后一个字符的后缀,长度是介于(p->fa->len,p->len]之间的,个数也就清楚了。

而且这个其实是动态变化的,每加入一个字符,就可以知道新加了几个不同子串。

加个pos,记录位置,这样就很容易预处理了。

 

 

学了一天的后缀自动,在世界冠军cxlove的博客中一直看SAM,终于有点理解了,Orz,太神奇了。

 

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <iostream>
  5 using namespace std;
  6 
  7 const int CHAR = 26;
  8 const int MAXN = 2020;
  9 struct SAM_Node
 10 {
 11     SAM_Node *fa,*next[CHAR];
 12     int len;
 13     int id,pos;
 14     SAM_Node(){}
 15     SAM_Node(int _len)
 16     {
 17         fa = 0;
 18         len = _len;
 19         memset(next,0,sizeof(next));
 20     }
 21 };
 22 SAM_Node SAM_node[MAXN*2], *SAM_root, *SAM_last;
 23 int SAM_size;
 24 SAM_Node *newSAM_Node(int len)
 25 {
 26     SAM_node[SAM_size] = SAM_Node(len);
 27     SAM_node[SAM_size].id = SAM_size;
 28     return &SAM_node[SAM_size++];
 29 }
 30 SAM_Node *newSAM_Node(SAM_Node *p)
 31 {
 32     SAM_node[SAM_size] = *p;
 33     SAM_node[SAM_size].id = SAM_size;
 34     return &SAM_node[SAM_size++];
 35 }
 36 void SAM_init()
 37 {
 38     SAM_size = 0;
 39     SAM_root = SAM_last = newSAM_Node(0);
 40     SAM_node[0].pos = 0;
 41 }
 42 void SAM_add(int x,int len)
 43 {
 44     SAM_Node *p = SAM_last, *np = newSAM_Node(p->len+1);
 45     np->pos = len;
 46     SAM_last = np;
 47     for(;p && !p->next[x];p = p->fa)
 48         p->next[x] = np;
 49     if(!p)
 50     {
 51         np->fa = SAM_root;
 52         return;
 53     }
 54     SAM_Node *q = p->next[x];
 55     if(q->len == p->len + 1)
 56     {
 57         np->fa = q;
 58         return;
 59     }
 60     SAM_Node *nq = newSAM_Node(q);
 61     nq->len = p->len + 1;
 62     q->fa = nq;
 63     np->fa = nq;
 64     for(;p && p->next[x] == q;p = p->fa)
 65         p->next[x] = nq;
 66 }
 67 void SAM_build(char *s)
 68 {
 69     SAM_init();
 70     int len = strlen(s);
 71     for(int i = 0;i < len;i++)
 72         SAM_add(s[i] - 'a',i+1);
 73 }
 74 
 75 int Q[MAXN][MAXN];
 76 char str[MAXN];
 77 int main()
 78 {
 79     int T;
 80     scanf("%d",&T);
 81     while(T--)
 82     {
 83         scanf("%s",str);
 84         int n = strlen(str);
 85         memset(Q,0,sizeof(Q));
 86         for(int i = 0;i < n;i++)
 87         {
 88             SAM_init();
 89             for(int j = i;j < n;j++)
 90             {
 91                 SAM_add(str[j]-'a',j-i+1);
 92             }
 93             for(int j = 1;j < SAM_size;j++)
 94             {
 95                 Q[i][SAM_node[j].pos-1+i]+=SAM_node[j].len - SAM_node[j].fa->len;
 96             }
 97             for(int j = i+1;j < n;j++)
 98                 Q[i][j] += Q[i][j-1];
 99         }
100         int M;
101         int u,v;
102         scanf("%d",&M);
103         while(M--)
104         {
105             scanf("%d%d",&u,&v);
106             u--;v--;
107             printf("%d\n",Q[u][v]);
108         }
109     }
110     return 0;
111 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/p/3239825.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞