您的位置:首页 > 其它

bzoj 3230: 相似子串 (后缀数组+RMQ+二分)

2016-12-29 23:31 375 查看

3230: 相似子串

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 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 3

ababa

3 5

5 9

8 10

Sample Output

18

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'组成

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: