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
题意: 给一个字符串长度最大2000,给出Q个查询[l,r]包含多少种连续的子串。
解析: 后缀自动机轻松过,先对查询离线排序,对于左端点相同的建立一个后缀自动
机,字符串长度最大只有2000,所以最后只用建2000个,每个sam插入的字符最多也就
2000,时间肯定是够的。
代码
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const int maxn=4005; struct SAM { int ch[maxn][26]; int pre[maxn],step[maxn]; int last,id; void init() { last=id=0; memset(ch[0],-1,sizeof(ch[0])); pre[0]=-1; step[0]=0; } void Insert(int c) //字符转化为数 { int p=last,np=++id; step[np]=step[p]+1; memset(ch[np],-1,sizeof(ch[np])); while(p!=-1&&ch[p][c]==-1) ch[p][c]=np,p=pre[p]; if(p==-1) pre[np]=0; else { int q=ch[p][c]; if(step[q]!=step[p]+1) { int nq=++id; memcpy(ch[nq],ch[q],sizeof(ch[q])); step[nq]=step[p]+1; pre[nq]=pre[q]; pre[np]=pre[q]=nq; while(p!=-1&&ch[p][c]==q) ch[p][c]=nq,p=pre[p]; } else pre[np]=q; } last=np; } int GetCnt() { int ret=0; for(int i=id;i>=1;i--) ret+=step[i]-step[pre[i]]; return ret; } }sam; char S[maxn/2]; struct Ques { int l,r,id; Ques(int l=0,int r=0,int id=0):l(l),r(r),id(id){} bool operator < (const Ques& t) const { if(l!=t.l) return l<t.l; return r<t.r; } }q[10005]; int Q,ans[10005]; void solve() { sort(q,q+Q); int last; for(int i=0;i<Q;i++) { if(i==0||q[i].l!=q[i-1].l) { sam.init(); last=q[i].l; } for(;last<=q[i].r;last++) sam.Insert(S[last]-‘a‘); ans[q[i].id]=sam.GetCnt(); } for(int i=0;i<Q;i++) printf("%d\n",ans[i]); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",S+1); int len=strlen(S); scanf("%d",&Q); int l,r,id; for(int i=0;i<Q;i++) { scanf("%d%d",&l,&r); q[i]=Ques(l,r,i); } solve(); } return 0; }