分析
如果height数组中存在一个区间宽度为W,且区间中每个值都大于等于H。那么这个区间对应的每个后缀,有长为H的公共前缀。也就是说这个区间产生了出现次数为W+1的长度为1~H的子串。
从大小较小的height开始计算,计算大的height时减去小height的贡献统计答案即可。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=100050;
char str[maxn];
int n;
namespace suffixArray {
int sa[maxn],x[maxn],c[maxn],t[maxn];
bool cmp(int u,int v,int l) {
return x[u]==x[v]&&(u+l>n?0:x[u+l])==(v+l>n?0:x[v+l]);
}
void da() {
int m=255;
for(int i = 0; i <= m; ++i) c[i]=0;
for(int i = 1; i <= n; ++i) c[x[i]=str[i]]++;
for(int i = 1; i <= m; ++i) c[i]+=c[i-1];
for(int i = n; i >= 1; --i) sa[c[x[i]]--]=i;
for(int l = 1; l <= n; l<<=1) {
int cnt=0;
for(int i = n-l+1; i <= n; ++i) t[++cnt]=i;
for(int i = 1; i <= n; ++i) {
if(sa[i]>l) t[++cnt]=sa[i]-l;
}
for(int i = 0; i <= m; ++i) c[i]=0;
for(int i = 1; i <= n; ++i) c[x[i]]++;
for(int i = 0; i <= m; ++i) c[i]+=c[i-1];
for(int i = n; i >= 1; --i) sa[c[x[t[i]]]--]=t[i];
m=0,t[sa[1]]=++m;
for(int i = 2; i <= n; ++i) {
if(cmp(sa[i],sa[i-1],l)) t[sa[i]]=m;
else t[sa[i]]=++m;
}
swap(x,t);
if(m==n) break;
}
}
int height[maxn],*rank=x;
void calHeight() {
for(int i = 1; i <= n; ++i) rank[sa[i]]=i;
int h=0;
for(int i = 1; i <= n; ++i) {
if(h) --h;
while(str[i+h]==str[sa[rank[i]-1]+h]) ++h;
height[rank[i]]=h;
}
}
}
void deb(int *arr,string s="") {
cout<<s<<endl;
for(int i = 1; i <= n; ++i) {
cout<<arr[i]<<" ";
}
cout<<endl;
}
int q[maxn],R[maxn],L[maxn];
ll calc(int N) {
using suffixArray::height;
ll ans=0;
if(N==1) {
ans=(ll)n*(n+1)/2;
height[n+1]=height[1]=0;
for(int i = 2; i <= n; ++i) {
ans-=height[i];
}
}
else {
set<pair<int,int> > st;
height[n+1]=height[1]=0;
for(int i = 2; i <= n; ++i) {
if(st.count({L[i],R[i]})) continue;
if(R[i]-L[i]+2>=N) {
ans+=(height[i]-max(height[L[i]-1],height[R[i]+1]));
}
st.insert({L[i],R[i]});
}
}
return ans;
}
int main() {
while(~scanf("%s", str+1)) {
using namespace suffixArray;
n=strlen(str+1);
da();calHeight();
int top=0;
for(int i = n; i >= 2; --i) {
while(top&&height[i]<=height[q[top]]) --top;
if(top) R[i]=q[top]-1;
else R[i]=n;
q[++top]=i;
}
top=0;
for(int i = 2; i <= n; ++i) {
while(top&&height[i]<=height[q[top]]) --top;
if(top) L[i]=q[top]+1;
else L[i]=2;
q[++top]=i;
}
int A,B;
scanf("%d%d", &A,&B);
printf("%lld
", calc(A)-calc(B+1));
}
return 0;
}