bzoj 3230: 相似子串 (后缀数组+RMQ+二分)
2016-12-29 23:31
375 查看
3230: 相似子串
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1502 Solved: 364
[Submit][Status][Discuss]
Description
Input
输入第1行,包含3个整数N,Q。Q代表询问组数。第2行是字符串S。
接下来Q行,每行两个整数i和j。(1≤i≤j)。
Output
输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。Sample Input
5 3ababa
3 5
5 9
8 10
Sample Output
1816
-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'组成
Source
后缀数组+二分+RMQ[Submit][Status][Discuss]
题解:后缀数组+二分+RMQ
因为是本质不同的,所以我们直接可以得到每个位置为止的子串的个数,然后可以二分答案,求出排名为k的串在哪个后缀中,并且在后缀中的长度。
知道排名,然后RMQ求解即可。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 100003 #define M 20 #define LL long long using namespace std; int n,m,len,q,p,st[20] ,l ; int sa ,rank ,height ,xx ,yy ,*x,*y,a ,b ; int sa1 ,rank1 ,height1 ,st1[20] ; LL sum ; char s ; struct data{ int pos,x; }; int cmp(int i,int j,int l) { return y[i]==y[j]&&(i+l>len?-1:y[i+l])==(j+l>len?-1:y[j+l]); } void get_SA(int sa ,int rank ,int height ,int st[M] ){ m=200; x=xx; y=yy; memset(b,0,sizeof(b)); for (int i=1;i<=len;i++) b[x[i]=a[i]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=len;i>=1;i--) sa[b[x[i]]--]=i; for (int k=1;k<=len;k<<=1) { p=0; for (int i=len-k+1;i<=len;i++) y[++p]=i; for (int i=1;i<=len;i++) if (sa[i]>k) y[++p]=sa[i]-k; for (int i=1;i<=m;i++) b[i]=0; for (int i=1;i<=len;i++) b[x[y[i]]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=len;i>=1;i--) sa[b[x[y[i]]]--]=y[i]; swap(x,y); p=2; x[sa[1]]=1; for (int i=2;i<=len;i++) x[sa[i]]=cmp(sa[i-1],sa[i],k)?p-1:p++; if (p>len) break; m=p+1; } p=0; for (int i=1;i<=len;i++) rank[sa[i]]=i; for (int i=1;i<=len;i++) { if (rank[i]==1) continue; int j=sa[rank[i]-1]; while (i+p<=len&&j+p<=len&&a[i+p]==a[j+p]) p++; height[rank[i]]=p; p=max(p-1,0); } for (int i=1;i<=len;i++) st[0][i]=height[i]; for (int i=1;i<=17;i++) for (int j=1;j+(1<<i)-1<=len;j++) st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]); int j=0; for (int i=1;i<=len;i++){ if ((1<<(j+1))<=i) j++; l[i]=j; } } data solve(LL x) { int l=1; int r=len; int ans=0; while (l<=r) { int mid=(l+r)/2; if(sum[mid]>=x&&sum[mid-1]<x) { ans=mid; break; } if (sum[mid]>x) r=mid-1; else l=mid+1; } LL t=x-sum[ans-1]; data a; a.pos=ans; a.x=height[ans]+(int)t; return a; } int calc(int x,int y) { if (x==y) return len; if (x>y) swap(x,y); int k=l[y-x]; x++; return min(st[k][x],st[k][y-(1<<k)+1]); } int calc1(int x,int y) { x=rank1[x]; y=rank1[y]; if (x==y) return len; if (x>y) swap(x,y); int k=l[y-x]; x++; return min(st1[k][x],st1[k][y-(1<<k)+1]); } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&len,&q); scanf("%s",s+1); for (int i=1;i<=len;i++) a[i]=s[i]-'a'+1; get_SA(sa,rank,height,st); for (int i=1;i<=len;i++) sum[i]=(LL)(len-sa[i]+1-height[i]); for (int i=1;i<=len;i++) sum[i]+=sum[i-1]; for (int i=1;i<=len;i++) a[len-i+1]=s[i]-'a'+1; get_SA(sa1,rank1,height1,st1); for (int i=1;i<=q;i++) { LL x,y; scanf("%I64d%I64d",&x,&y); if(x>sum[len]||y>sum[len]) { printf("-1\n"); continue; } data ansl=solve(x); data ansr=solve(y); int ll=sa[ansl.pos]+ansl.x-1; int rr=sa[ansr.pos]+ansr.x-1; int a=min(min(ansl.x,ansr.x),calc(ansl.pos,ansr.pos)); int b=min(min(ansl.x,ansr.x),calc1(len-ll+1,len-rr+1)); LL ans=(LL)a*(LL)a+(LL)b*(LL)b; printf("%lld\n",ans); } return 0; }
相关文章推荐
- bzoj 3230: 相似子串 后缀数组+rmq+二分
- bzoj3230 相似子串(SA+lcp+二分)
- [BZOJ3230]相似子串(后缀数组+二分+st表)
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
- [BZOJ3230]相似子串(后缀数组+二分+ST表)
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
- BZOJ 3230 相似子串 | 后缀数组 二分 ST表
- BZOJ3230 相似子串 【后缀数组】
- 相似子串 bzoj3230
- BZOJ 3230 相似子串 后缀数组
- BZOJ3230 相似子串
- BZOJ 3230: 相似子串
- BZOJ 3230 相似子串|后缀数组|RMQ
- BZOJ 3230 相似子串 后缀数组+二分+ST表
- BZOJ3230 相似子串 【后缀数组】
- bzoj 3230 相似子串 后缀数组
- BZOJ 3230 相似子串 ——后缀数组
- bzoj 3230 相似子串
- BZOJ 3230:相似子串
- [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)