Reincarnation
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.
是谁说这题是后缀自动机入门题的……想了好久……
//掀桌.jpg
┏┻┻┻┻┻┻┻┓ | |
┃ ┏┓ ┏┓ ┃ | |
┃ ┗┛ A┗┏━┓ ┏━┓━━┻━━━━━━━┻━━━
┗━━━━━┗━┛ ┗━┛
| |
这真的是一道入门题???而不是一道进阶题???
我还是太弱了╮( ̄▽ ̄”)╭~~
思路:
由于咱水平有限,后缀自动机在这题只是负责数数的……
思路是预处理,对于原串每一个后缀建一次自动机。
由于自动机的性质,加一个点增加的方案数就是以该点为后缀的子串个数。
所以爆枚起点(0-n)并对每一个起点建自动机。
这时每插入一个新节点就能处理出从当前起点到当前新节点的方案数了。
预处理出表后直接查表即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=5233;
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
int ans[2333][2333];
struct SAM
{
int next[N][26],fa[N],len[N],cnt[N];
int pool,u;
void init()
{
pool=u=1;
memset(next,0,sizeof(next));
memset(len,0,sizeof(len));
memset(cnt,0,sizeof(cnt));
memset(fa,0,sizeof(fa));
cnt[pool]=1;
}
int insert(int v)
{
int now=++pool;
len[now]=len[u]+1;
while(!next[u][v] && u)
cnt[now]+=cnt[u],next[u][v]=now,u=fa[u];
if(!u)
fa[now]=1;
else
{
int q=next[u][v];
if(len[q]==len[u]+1)
fa[now]=q;
else
{
int newq=++pool;
memcpy(next[newq],next[q],sizeof(next[q]));
len[newq]=len[u]+1;
fa[newq]=fa[q];
cnt[newq]=0;
fa[now]=fa[q]=newq;
while(next[u][v]==q && u)
{
cnt[next[u][v]]-=cnt[u];
cnt[newq]+=cnt[u];
next[u][v]=newq,u=fa[u];
}
}
}
u=now;
return now;
}
}koishi;
int main()
{
int T=read();
char s[N];
while(T--)
{
scanf("%s",&s);
int len=strlen(s);
for(int i=0;i<len;i++)
{
koishi.init();
for(int j=i;j<len;j++)
{
koishi.insert(s[j]-'a');
ans[i][j]=koishi.cnt[koishi.u];
}
for(int j=i+1;j<len;j++)
ans[i][j]+=ans[i][j-1];
}
int q=read();
while(q--)
{
int a=read(),b=read();
printf("%d\n",ans[a-1][b-1]);
}
}
return 0;
}