HDU 4622 Reincarnation 后缀自动机

Posted Meek

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 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.
 

题意:

  给你一个母串,

  Q个询问,每次询问你[L,R] 属于这一段中不同子串的个数是多少

题解:

  考虑离线

  把询问缩小,相同L的询问划分为一类

  这样最多就是建立 2000 个后缀自动机了

#include <bits/stdc++.h>
inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}return x*f;}
using namespace std;

const int N = 2e3+7;

const long long mod = 1000000007;

long long now;
int isPlus[N * 2],endpos[N * 2];int d[N * 2];
int tot,slink[2*N],trans[2*N][28],minlen[2*N],maxlen[2*N],pre;
int newstate(int _maxlen,int _minlen,int* _trans,int _slink){
    maxlen[++tot]=_maxlen;minlen[tot]=_minlen;
    slink[tot]=_slink;
    if(_trans)for(int i=0;i<26;i++)trans[tot][i]=_trans[i],d[_trans[i]]+=1;
    return tot;
}
long long update(int u) {
    return 1LL*(maxlen[u] - minlen[u] + 1);
}
int add_char(char ch,int u){
    int c=ch-a,v=u;
    int z=newstate(maxlen[u]+1,-1,NULL,0);
    isPlus[z] = 1;
    while(v&&!trans[v][c]){trans[v][c]=z;d[z]+=1;v=slink[v];}
    if(!v){ minlen[z]=1;slink[z]=1;now += update(z);return z;}
    int x=trans[v][c];
    if(maxlen[v]+1==maxlen[x]){slink[z]=x;minlen[z]=maxlen[x]+1;now += update(z);return z;}
    int y=newstate(maxlen[v]+1,-1,trans[x],slink[x]);
    now -= update(x);
    slink[z]=slink[x]=y;minlen[x]=minlen[z]=maxlen[y]+1;
    now += update(x);
    while(v&&trans[v][c]==x){trans[v][c]=y;d[x]--,d[y]++;v=slink[v];}
    minlen[y]=maxlen[slink[y]]+1;
    now += update(y);now += update(z);
    return z;
}
void init_sam() {
    for(int i = 1; i <= tot; ++i)
        for(int j = 0; j < 26; ++j) trans[i][j] = 0;
    pre = tot = 1;

}
int T,n;
long long ans[20000];
char a[N * 2];
struct ss{int L,R,id;}Q[20000];
int cmp(ss s1,ss s2) {
    if(s1.L == s2.L)return s1.R < s2.R;
    return s1.L < s2.L;
}
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%s%d",a+1,&n);
        for(int i = 1; i <= n; ++i)
            scanf("%d%d",&Q[i].L,&Q[i].R),Q[i].id = i;
        sort(Q+1,Q+n+1,cmp);
        int l = 1,r = 0;
        for(int i = 1; i <= n; ++i) {
            if(Q[i].L != Q[i-1].L) {init_sam();
                l = Q[i].L,r = l-1;
                now = 0;
            }
            while(r < Q[i].R){
                pre = add_char(a[(++r)],pre);
            }
            ans[Q[i].id] = now;
        }
        for(int i = 1; i <= n; ++i) printf("%lld\n",ans[i]);
    }
    return 0;
}

 

以上是关于HDU 4622 Reincarnation 后缀自动机的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4622 Reincarnation 后缀自动机

HDU4622 Reincarnation 后缀自动机

HDU 4622 Reincarnation(后缀自动机)

HDU4622:Reincarnation(后缀数组,求区间内不同子串的个数)

HDU 4622 Reincarnation (区间不相同子串个数:字符串哈希 | 后缀数组 | 后缀自动机)

HDU 4622 Reincarnation(SAM)