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.
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.
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.
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
3
1
7
5
8
1
3
8
5
1
I won't do anything against hash because I am nice.Of course this problem has a solution that don't rely on hash. 给你一个串 m个询问 询问 区间l,r的不同子串个数,因为有a,b限制,所以每次比较tmp的和rmq就行,保留减的时候保留小的那个,更新大的那个。
后缀自动机的 解法#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN = 3010; int t1[MAXN],t2[MAXN],c[MAXN]; int len1,len2; bool cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(char str[],int sa[],int ra[],int height[],int n,int m) { n++; int i,j,p,*x=t1,*y=t2; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[i]=str[i]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(j=1;j<=n;j<<=1) { p=0; for(i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[y[i]]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; if(p>=n) break; m=p; } int k=0; n--; for(i=0;i<=n;i++) ra[sa[i]]=i; for(i=0;i<n;i++) { if(k) k--; j=sa[ra[i]-1]; while(str[i+k]==str[j+k])k++; height[ra[i]]=k; } } int ra[MAXN],height[MAXN]; int sa[MAXN]; char str[MAXN]; int lo[MAXN]; int ans[MAXN]; int st[MAXN][20]; void init(int n) { lo[0]=-1; for(int i=1;i<=n;i++) lo[i]=lo[i>>1]+1; for(int i=1;i<=n;i++) st[i][0]=height[i]; for(int i=1;i<=lo[n];++i) for(int j=1;j<=n;j++) if(j+(1<<i-1)<=n) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]); } inline int rmq(int l,int r) { if(l>r) return 0; int k=lo[r-l+1]; return min(st[l][k],st[r-(1<<k)+1][k]); } int main() { int t; scanf("%d",&t); while(t--) { int q; scanf(" %s",str); int len=strlen(str); da(str,sa,ra,height,len,130); init(len); scanf("%d",&q); while(q--) { int a,b; scanf("%d%d",&a,&b); a--,b--; int tot=0; for(int i=a;i<=b;i++) ans[tot++]=ra[i]; sort(ans,ans+tot); long long res=max(0,b+1-sa[ans[0]]); long long tmp=res; for(int i=1;i<tot;i++) { tmp=min(1ll*rmq(ans[i-1]+1,ans[i]),tmp); res+=max(0ll,1ll*b+1-sa[ans[i]]-tmp); tmp=max(tmp,1ll*b+1-sa[ans[i]]); } printf("%lld\n",res ); } } }
建造n个自动机即可,无脑解法,因为k是拆分出来的,所以不用算进去。
#include <bits/stdc++.h> using namespace std; const int maxn = 6010+5; int last,tail,Min[maxn]; int Max[maxn],vis[maxn]; int nxt[maxn][26],fail[maxn]; char sa[maxn],sb[maxn]; typedef long long ll; int tot; int build(char s) { int p=last,t=++tail,c=s-'a'; Max[t]=Max[p]+1; memset(nxt[p],0,sizeof(nxt[p])); while(p&&!nxt[p][c]) nxt[p][c]=t,p=fail[p]; if(p) { int q=nxt[p][c]; if(Max[q]==Max[p]+1) fail[t]=q,Min[t]=Max[q]+1; else { int k=++tail; fail[k]=fail[q]; fail[t]=fail[q]=k; Max[k]=Max[p]+1; // tot+=Max[k]-Max[fail[k]]; memcpy(nxt[k],nxt[q],sizeof(nxt[q])); while(p&&nxt[p][c]==q) nxt[p][c]=k,p=fail[p]; } } else fail[t]=Min[t]=1; last=t; tot+=Max[t]-Max[fail[t]]; return tot; } char str[3010]; int an[3010][3010]; int main() { int t; scanf("%d",&t); while(t--) { scanf(" %s",str); int len=strlen(str); for(int i=0;i<len;i++) { last=1,tail=1; memset(nxt[1],0,sizeof(nxt[1])); tot=0; for(int j=i;j<len;j++) an[i][j]=build(str[j]); } int q; scanf("%d",&q); while(q--) { int a,b; scanf("%d%d",&a,&b); a--,b--; printf("%d\n",an[a][b] ); } } }