HDU-4622 Reincarnation (后缀自动机)

题意:给定一个字符串,多组询问,每个询问给一个区间,求出该区间内共有多少个不同的子串。

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

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

N<=2000.

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

建立n次后缀自动机。

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

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

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

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

  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 }

 

posted @ 2017-10-19 23:21  抓不住Jerry的Tom  阅读(291)  评论(0编辑  收藏  举报