这个题思路应该算是比较简单的……
先扫一遍height,算出前i个后缀中含有的不同子串个数,然后在这个和中二分,找到一个排名对应的子串。
然后就是最长公共前缀和最长公共后缀……用两个后缀数组即可完成所有操作。
但是我有两个之前写错了的地方:
1、没有开long long
2、注意算LCP的时候,要算RMQ(rank[p]+1,rank[q]),但如果rank[p],rank[q]大小关系未知,则应该先判断是否应当交换。注意交换的是rank[p]和rank[q],而不是rank[p]+1和rank[q],这里注意特判。
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> using namespace std; typedef long long LL; const int MAXN=100010; const int INF=1000000000; int n,Q; int sa[MAXN],c[MAXN],t1[MAXN],t2[MAXN],rank[MAXN],height[MAXN]; int ST[MAXN][25],Log[MAXN]; int l1[MAXN],r1[MAXN],l2[MAXN],r2[MAXN]; LL ans[MAXN],num[MAXN],x,y; char s[MAXN]; void BuildSA(int m) { int *x=t1,*y=t2; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[i]=s[i]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;;k<<=1) { int p=0; for(int i=n-k;i<n;i++) y[p++]=i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1,x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p-1:p++; m=p; if(p>=n) break; } } void GetHeight() { int k=0; for(int i=0;i<n;i++) rank[sa[i]]=i; for(int i=0;i<n-1;i++) { int j=sa[rank[i]-1]; if(k>0) k--; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } void initRMQ() { for(int i=1;i<n;i++) ST[i][0]=height[i]; for(int i=1;i<=Log[n-1];i++) for(int j=1;j<n-(1<<(i-1));j++) ST[j][i]=min(ST[j][i-1],ST[j+(1<<(i-1))][i-1]); } int RMQ(int l,int r) { if(l>r) swap(l,r); int x=Log[r-l+1]; return min(ST[l][x],ST[r-(1<<x)+1][x]); } int main() { scanf("%d%d%s",&n,&Q,s); n++; BuildSA(256); GetHeight(); for(int i=1;i<n;i++) num[i]=num[i-1]+(LL)(n-1-sa[i])-(LL)height[i]; for(int i=1;i<=Q;i++) { scanf("%lld%lld",&x,&y); if(x>num[n-1]||y>num[n-1]) {l1[i]=-1;continue;} l1[i]=lower_bound(num+1,num+n,x)-num; r1[i]=sa[l1[i]]+x-num[l1[i]-1]-1+height[l1[i]]; l1[i]=sa[l1[i]]; l2[i]=lower_bound(num+1,num+n,y)-num; r2[i]=sa[l2[i]]+y-num[l2[i]-1]-1+height[l2[i]]; l2[i]=sa[l2[i]]; } Log[0]=-1; for(int i=1;i<=n;i++) Log[i]=Log[i>>1]+1; initRMQ(); for(int i=1;i<=Q;i++) if(l1[i]!=-1) { int p=rank[l1[i]],q=rank[l2[i]]; if(p>q) swap(p,q); LL x=RMQ(p+1,q); if(l1[i]==l2[i]) x=INF; x=min(x,(LL)min(r1[i]-l1[i]+1,r2[i]-l2[i]+1)); ans[i]+=x*x; } reverse(s,s+n-1); BuildSA(256); GetHeight(); initRMQ(); for(int i=1;i<=Q;i++) if(l1[i]!=-1) { int p=n-2-r1[i],q=n-2-r2[i]; p=rank[p],q=rank[q]; if(p>q) swap(p,q); LL x=RMQ(p+1,q); if(r1[i]==r2[i]) x=INF; x=min(x,(LL)min(r1[i]-l1[i]+1,r2[i]-l2[i]+1)); ans[i]+=x*x; } for(int i=1;i<=Q;i++) { if(l1[i]==-1) puts("-1"); else printf("%lld\n",ans[i]); } return 0; }