HDU 4622 Reincarnation

来源:互联网 发布:程序员有含金量的证书 编辑:程序博客网 时间:2024/06/07 13:45

ProblemDescription

Now you are back,andhave a task to do:
Given you a string s consist of lower-case English letters only,denote f(s) asthe 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 linecontains 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 numberof queries.
Then Q lines follows,each lines contains two integer l, r(1 <= l <= r<= n), denote a query.

 

 

Output

For each testcases,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

题目大意:给一个字符串,进行q次询问,求lr之间的字符串有多少个不同子串。

方法:开始用后缀数组暴力做的,结果果断T掉了。后来看了看CLJ的后缀自动机,然后在网上有查了些后缀自动机的资料(感觉这篇写得不错。http://blog.csdn.net/xuezhongfenfei/article/details/12262941)就试着用后缀自动机写了。对于后缀自动机。我们先将lr按照l从小到大,排序。对于l相同,r从小到大排序。这样对于l相同的询问,就可以利用后缀自动机的特性往后面加字符得到答案。对于l不同的询问,就重新建立自动机。

 

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<deque>#include<algorithm>using namespace std;struct NODE{int left ,right;int num;};struct State{State *pre ,*go[26];//pre是上一个可以接收后缀的结点int val;};State * root ,* tail ,que[4010];NODE nodes[10010];int ans[10010];int n ,q ,tot ,sum ,len;char str[2010];int cmp(NODE a ,NODE b){if(a.left==b.left){return a.right < b.right;}return a.left < b.left;}void init(){memset(que,0,sizeof(que));tot = 0;len = 0;root = tail = &que[tot++];}void add(int w ){State *p = tail ,*np = &que[tot++];np->val = len;//找到上一个能接受后缀的节点while(p && p->go[w]==NULL){p->go[w] = np;p = p->pre;}//如果没有找到这样的节点,就将pre指针指向rootif(p==NULL){np->pre = root;}//如果找到这样的节点,就把这个节点pre就指向这个节点对应的儿子else{State *q = p->go[w];if(p->val + 1==q->val){np->pre = q;}else{State *nq = &que[tot++];//将q的指针赋值给nq,将nq的pre指向p,将np和q的pre指向nq*nq = *q;nq->val = p->val + 1;q->pre = np->pre = nq;//同时将p的儿子为w且指向q的全部指向nqwhile(p && p->go[w]==q){p->go[w] = nq;p = p->pre;}}}tail = np;}int solve(){    sum = 0;    for(int i = tot - 1;i > 0;i--)    {       sum += que[i].val - que[i].pre->val;    }return sum;}int main(){int x;scanf("%d",&n);while(n--){scanf("%s",str+1);scanf("%d",&q);for(int i = 1;i<=q;i++)        {scanf("%d%d",&nodes[i].left,&nodes[i].right);nodes[i].num = i;        }sort(nodes + 1,nodes + q + 1,cmp);nodes[0].left = -1;for(int i = 1;i<=q;i++){if(nodes[i].left!=nodes[i-1].left){init();for(int j = nodes[i].left;j <= nodes[i].right;j++){len++;add(str[j] - 'a');}ans[nodes[i].num] = solve();x = nodes[i].right + 1;}else{if(nodes[i].right==nodes[i-1].right){ans[nodes[i].num] = ans[nodes[i-1].num];}else{for(int j = x;j <= nodes[i].right;j++){len++;add(str[j] - 'a');}ans[nodes[i].num] = solve();x = nodes[i].right + 1;}}}for(int i = 1;i <= q;i++){printf("%d\n",ans[i]);}}return 0;}


 

0 0
原创粉丝点击