题意:
给出一个字符串,和一个上下界,求所有子串中出现次数恰好介于上下界的个数。
题解:
假设上下界为x、y,我们计算出出现次数大于k的数目cal(k),那么cal(x)-cal(y+1)就是答案。
先上后缀数组板子求出rank、sa和height数组
我们按rank从小到大排序,相邻k个位一组,即1~k、2~k+1、3~k+2、4~k+3。。。。。。
对于1~k,假设这一组的height的最小值为c,那么就有c个字符串的出现次数至少为k,这是显然易见的。
对于2~k+1,假设这一组的height的最小值为c’,如果c’>c那么又多出(c’-c)个字符串的出现次数至少为k,
如果c’<c,那么对答案没有贡献。
总结一下,如果本组height的最小值比上一组多,那么对答案贡献差值个,如果比上一组少,则没有贡献。
代码:
#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lower_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
char s[N];
int sa[N],t[N],t2[N],c[N],n,rak[N],height[N],f[18][N];
void build_sa(int m,char *s)
{
int i,*x=t,*y=t2;
for (i=0;i<m;i++)c[i]=0;
for (i=0;i<n;i++)c[x[i]=s[i]]++;
for (i=1;i<m;i++)c[i]+=c[i-1];
for (i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for (int k=1;k<=n;k<<=1)
{
int p=0;
for (i=n-k;i<n;i++)y[p++]=i;
for (i=0;i<n;i++)if (sa[i]>=k)y[p++]=sa[i]-k;
for (i=0;i<m;i++)c[i]=0;
for (i=0;i<n;i++)c[x[y[i]]]++;
for (i=0;i<m;i++)c[i]+=c[i-1];
for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1; x[sa[0]]=0;
for (i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if (p>=n) break;
m=p;
}
}
void getheight()
{
int k=0;
for (int i=0;i<n;i++)rak[sa[i]]=i;
for (int i=0;i<n;i++)
{
if (k)k--;
if (!rak[i])continue;
int j=sa[rak[i]-1];
while (s[i+k]==s[j+k])k++;
height[rak[i]]=k;
}
for (int i=0;i<n;i++) f[0][i]=height[i];
for (int j=1;(1<<j)<n;j++)
for (int i=0;i<n;i++)if (i+(1<<(j-1)) <n)
f[j][i]=min(f[j-1][i],f[j-1][i+(1<<(j-1))]);
}
int qu(int x,int y)
{
if (x==y) return f[0][x];
int k=31-__builtin_clz(y-x);
return min(f[k][x],f[k][y-(1<<k)+1]);
}
LL cal(int k)
{
if (k==1)
{
LL res=n-sa[1]-1;
for (int i=2;i<n;i++) res+=n-sa[i]-height[i]-1;
return res;
}else
if (k>n)return 0;else
{
LL res=0,m=0;
for (int i=0;i+k-1<n;i++)
{
int t=qu(i+1,i+k-1);
if (t>m) res+=t-m;
m=t;
}
return res;
}
}
int main()
{
while (~scanf("%s",s))
{
n=strlen(s); s[n]='#'; n++;
build_sa(200,s);
getheight();
int x,y;
scc(x,y);
printf("%lld\n",cal(x)-cal(y+1));
}
return 0;
}