3230: 相似子串
Posted copyright
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3230: 相似子串相关的知识,希望对你有一定的参考价值。
Description
Input
输入第1行,包含3个整数N,Q。Q代表询问组数。
第2行是字符串S。
接下来Q行,每行两个整数i和j。(1≤i≤j)。
Output
输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。
Sample Input
5 3
ababa
3 5
5 9
8 10
ababa
3 5
5 9
8 10
Sample Output
18
16
-1
16
-1
HINT
样例解释
第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。
第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。
第3组询问:不存在第10个子串。输出-1。
数据范围
N≤100000,Q≤100000,字符串只由小写字母\'a\'~\'z\'组成
建立后缀数组,h和pr数组。。。
查询字典序为i的串,我们知道以i开头的不同的字串是n-h[i]-sa[i]那么就可以二分的寻找i,
然后用线段树或者st算法预处理h,pr数组,然后每次查询即可。。。
代码来自黄学长。。
1 #include<map> 2 #include<set> 3 #include<cstdio> 4 #include<cstring> 5 #include<vector> 6 #include<cstdlib> 7 #include<iostream> 8 #include<algorithm> 9 #define inf 1000000000 10 #define ll long long 11 using namespace std; 12 ll read() 13 { 14 ll x=0,f=1;char ch=getchar(); 15 while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();} 16 while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();} 17 return x*f; 18 } 19 int n,m,Log[100005]; 20 char ch[100005]; 21 struct SA{ 22 int p,q,k; 23 int sa[2][100005],rk[2][100005],mn[17][100005]; 24 int a[100005],h[100005],v[100005];ll s[100005]; 25 SA(){ 26 p=0,q=1; 27 } 28 void mul(int *sa,int *rk,int *SA,int *RK){ 29 for(int i=1;i<=n;i++)v[rk[sa[i]]]=i; 30 for(int i=n;i;i--) 31 if(sa[i]>k)SA[v[rk[sa[i]-k]]--]=sa[i]-k; 32 for(int i=n-k+1;i<=n;i++)SA[v[rk[i]]--]=i; 33 for(int i=1;i<=n;i++) 34 RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i-1]]!=rk[SA[i]]||rk[SA[i-1]+k]!=rk[SA[i]+k]); 35 } 36 void getsa(){ 37 for(int i=1;i<=n;i++)v[a[i]]++; 38 for(int i=1;i<=30;i++)v[i]+=v[i-1]; 39 for(int i=1;i<=n;i++)sa[p][v[a[i]]--]=i; 40 for(int i=1;i<=n;i++) 41 rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]); 42 for(k=1;k<n;k<<=1,swap(p,q)) 43 mul(sa[p],rk[p],sa[q],rk[q]); 44 for(int k=0,i=1;i<=n;i++) 45 { 46 int j=sa[p][rk[p][i]-1]; 47 while(a[i+k]==a[j+k])k++; 48 h[rk[p][i]]=k;if(k)k--; 49 } 50 } 51 void pre(){ 52 for(int i=1;i<=n;i++)a[i]=ch[i]-\'a\'+1; 53 getsa(); 54 for(int i=1;i<=n;i++)mn[0][i]=h[i]; 55 for(int i=1;i<=Log[n];i++) 56 for(int j=1;j<=n;j++) 57 if(j+(1<<i)-1<=n) 58 mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<(i-1))]); 59 else break; 60 for(int i=1;i<=n;i++) 61 s[i]=s[i-1]+n-sa[p][i]+1-h[i]; 62 } 63 int query(int a,int b){ 64 a=rk[p][a],b=rk[p][b]; 65 if(a>b)swap(a,b);a++; 66 int t=Log[b-a+1]; 67 return min(mn[t][a],mn[t][b-(1<<t)+1]); 68 } 69 void print(){ 70 for(int i=2;i<=n;i++)printf("%d ",h[i]); 71 } 72 }A,B; 73 int main() 74 { 75 Log[0]=-1;for(int i=1;i<=100000;i++)Log[i]=Log[i>>1]+1; 76 n=read();m=read(); 77 scanf("%s",ch+1);A.pre(); 78 reverse(ch+1,ch+n+1);B.pre(); 79 for(int i=1;i<=m;i++) 80 { 81 ll l=read(),r=read(),id,a1,a2,b1,b2,ans=0; 82 if(l>A.s[n]||r>A.s[n]){puts("-1");continue;} 83 id=lower_bound(A.s+1,A.s+n+1,l)-A.s; 84 a1=A.sa[A.p][id]; 85 b1=A.sa[A.p][id]+A.h[id]-1+l-A.s[id-1]; 86 id=lower_bound(A.s+1,A.s+n+1,r)-A.s; 87 a2=A.sa[A.p][id]; 88 b2=A.sa[A.p][id]+A.h[id]-1+r-A.s[id-1]; 89 ll t=(a1==a2)?inf:A.query(a1,a2); 90 t=min(t,min(b1-a1+1,b2-a2+1));ans+=t*t; 91 t=(n-b1+1==n-b2+1)?inf:B.query(n-b1+1,n-b2+1); 92 t=min(t,min(b1-a1+1,b2-a2+1));ans+=t*t; 93 printf("%lld\\n",ans); 94 } 95 return 0; 96 }
以上是关于3230: 相似子串的主要内容,如果未能解决你的问题,请参考以下文章