【BZOJ3230】相似子串 后缀数组+二分+RMQ
【BZOJ3230】相似子串
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'组成
题解:一开始由于用SA还是SAM,然后看到下面的SOURCE一下子就不用犹豫了。。。这个提示也太明显了~
如何字典序第k小的子串呢?考虑二分,问题就变成了问一个子串的字典序,这个可以直接在height数组上求出,答案就是n-sa[i]-height[i]的前缀和。
然后相似程度就好求了,直接维护正串和反串的SA,用RMQ求出LCP即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn=100010; int n,m,Q; char str[maxn]; int Log[maxn]; ll s[maxn]; inline ll rd() { ll ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } struct SA { int ra[maxn],rb[maxn],r[maxn],st[maxn],sa[maxn],rank[maxn],h[maxn],f[18][maxn]; void build() { int *x=ra,*y=rb,i,j,k,p; for(i=0;i<n;i++) st[x[i]=r[i]]++; for(i=1;i<m;i++) st[i]+=st[i-1]; for(i=n-1;i>=0;i--) sa[--st[x[i]]]=i; for(j=p=1;p<n;j<<=1,m=p) { for(p=0,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++) st[i]=0; for(i=0;i<n;i++) st[x[y[i]]]++; for(i=1;i<m;i++) st[i]+=st[i-1]; for(i=n-1;i>=0;i--) sa[--st[x[y[i]]]]=y[i]; for(swap(x,y),i=p=1,x[sa[0]]=0;i<n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++; } for(i=1;i<n;i++) rank[sa[i]]=i; for(i=k=0;i<n-1;h[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); for(i=1;i<n;i++) f[0][i]=h[i]; for(j=1;(1<<j)<n;j++) for(i=1;i+(1<<j)-1<n;i++) f[j][i]=min(f[j-1][i],f[j-1][i+(1<<(j-1))]); } inline int query(int a,int b) { if(a==b) return n-a; a=rank[a],b=rank[b]; if(a>b) swap(a,b); a++; int k=Log[b-a+1]; return min(f[k][a],f[k][b-(1<<k)+1]); } }s1,s2; int find(ll x) { int l=1,r=n+1,mid; while(l<r) { mid=(l+r)>>1; if(s[mid]>=x) r=mid; else l=mid+1; } return r; } int main() { n=rd(),Q=rd(); scanf("%s",str); int i,c,d,la,lb; ll a,b; for(i=0;i<n;i++) s1.r[i]=s2.r[n-i-1]=str[i]-'a'+1; n++,m=27,s1.build(),m=27,s2.build(),n--; for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1; for(i=1;i<=n;i++) s[i]=s[i-1]+n-s1.sa[i]-s1.h[i]; for(i=1;i<=Q;i++) { a=rd(),b=rd(),c=find(a),la=a-s[c-1]+s1.h[c],d=find(b),lb=b-s[d-1]+s1.h[d]; if(c==n+1||d==n+1) printf("-1\n"); else { a=min(min(la,lb),s1.query(s1.sa[c],s1.sa[d])),b=min(min(la,lb),s2.query(n-s1.sa[c]-la,n-s1.sa[d]-lb)); printf("%lld\n",a*a+b*b); } } return 0; }//5 3 ababa 3 5 5 9 8 10
| 欢迎来原网站坐坐! >原文链接<