题目链接:https://nanti.jisuanke.com/t/A2018
题意:出现[L, R] 次的字符串的个数
题解:和这个题几乎一样:https://blog.csdn.net/mmk27_word/article/details/98210376,这样我们就固定左边界,找到至少出现L次的 - 至少出现R+1次的即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
const int N=110000;
int t1[N],t2[N],sum[N],rk[N],ht[N],sa[N],str[N],n;
char s[N];
void get_sa(int n,int m)
{
int *x=t1,*y=t2;
for(int i=0;i<m;i++) sum[i]=0;
for(int i=0;i<n;i++) sum[x[i]=str[i]]++;
for(int i=1;i<m;i++) sum[i]+=sum[i-1];
for(int i=n-1;i>=0;i--) sa[--sum[x[i]]]=i;
for(int p,j=1;p<=n;j<<=1)
{
p=0;
for(int i=n-j;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(int i=0;i<m;i++) sum[i]=0;
for(int i=0;i<n;i++) sum[x[y[i]]]++;
for(int i=1;i<m;i++) sum[i]+=sum[i-1];
for(int i=n-1;i>=0;i--) sa[--sum[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-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
if(p>=n) break;
m=p;
}
int k=0;n--;
for(int i=0;i<=n;i++) rk[sa[i]]=i;
for(int i=0;i<n;i++)
{
if(k)k--;else k=0;
int j=sa[rk[i]-1];
while(str[i+k]==str[j+k])k++;
ht[rk[i]]=k;
}
}
struct node {
int l, r;
int minn;
}tree[N<<2];
void build(int l, int r, int cur) {
tree[cur].l=l;
tree[cur].r=r;
if(l==r) {
tree[cur].minn=ht[l];
return;
}
int mid=(r+l)>>1;
build(l, mid, cur << 1);
build(mid + 1, r, cur << 1 | 1);
tree[cur].minn = min(tree[cur<<1].minn, tree[cur<<1|1].minn);
}
int query(int pl, int pr, int cur) {
if(pl <= tree[cur].l && tree[cur].r <= pr) {
return tree[cur].minn;
}
int res = N;
if(pl <= tree[cur<<1].r) res = min(res, query(pl, pr, cur << 1));
if(pr >= tree[cur<<1|1].l) res = min(res, query(pl, pr, cur << 1 | 1));
return res;
}
int main()
{
int T;
char s[100100];
int n,k;
ll ans1 , ans2;
int l, r;
int A, B;
int cnt;
while(~scanf("%s%d%d",s,&A,&B)) {
n=strlen(s);
for(int i=0;i<n;i++) str[i]=s[i];
str[n]=0;
get_sa(n+1,256);
ht[n+1]=0;
ans1 = ans2 = 0;
build(1,n,1);
ht[n + 1] = 0;
if(A == 1) {
ans1 = 1LL * n * (n + 1) / 2;
for(int i = 1; i <= n; i++) {
ans1 -= ht[i];
}
} else {
for(int i = 1; i <= n - A + 1; i++) {
l = i + 1, r = i + A - 1;
cnt = 0;
if(l <= r) cnt = query(l, r, 1);
ans1 += max(0, cnt - ht[i]);
}
}
B++;
if(B <= n) {
for(int i = 1; i <= n - B + 1; i++) {
l = i + 1, r = i + B - 1;
cnt = 0;
if(l <= r) cnt = query(l, r, 1);
ans2 += max(0, cnt - ht[i]);
}
}
printf("%lld\n", ans1 - ans2);
}
return 0;
}