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
 

 

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 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM