设字符串 str 长度为 l ,定义字符串 s 的哈希值为
1≤|s|,m≤100000
本题的难点在于如何求出哈希值的和,其它的我们直接离线,将询问差分,然后存在一个桶里面,排个序,求答案时我们直接按照排序后的顺序扫一遍,将可处理的询问处理了。
那么哈希值之和怎么求呢?
我们定义如下数组
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long LL;
const int N=100050;
const int M=100050;
const int P=12580;
const int D=26;
struct Q
{
LL K;
int id;
}qu[N<<1];
bool operator<(Q a,Q b)
{
return a.K<b.K;
}
int Ws[N],Wv[N],x[N],y[N],SA[N],rank[N],height[N],sum[N],p[N],hash[N],ans[M][3];
bool deal[M];
LL q[M][2];
char s[N];
int n,m;
void pre()
{
p[0]=D;
for (int i=1,j=D*D%P;i<=n;i++,(j*=D)%=P)
p[i]=(p[i-1]+j)%P;
hash[0]=s[0]-'a';
for (int i=1;i<n;i++)
hash[i]=((LL)hash[i-1]*D%P+(s[i]-'a'))%P;
sum[0]=hash[0];
for (int i=1;i<n;i++)
sum[i]=(sum[i-1]+hash[i])%P;
}
bool cmp(int *r,int i,int j,int l)
{
return r[i]==r[j]&&r[i+l]==r[j+l];
}
void DA()
{
int mx=0,l=1,p=0,i;
for (i=0;i<n;i++)mx=max(mx,Wv[i]=x[i]=s[i]-'a');
for (i=0;i<=mx;i++)Ws[i]=0;
for (i=0;i<n;i++)Ws[Wv[i]]++;
for (i=1;i<=mx;i++)Ws[i]+=Ws[i-1];
for (i=n-1;i>=0;i--)SA[--Ws[Wv[i]]]=i;
for (;l<=n&&p!=n;l<<=1)
{
for (p=0,i=n-l;i<n;i++)y[p++]=i;
for (i=0;i<n;i++)if(SA[i]>=l)y[p++]=SA[i]-l;
for (mx=0,i=0;i<n;i++)mx=max(mx,Wv[i]=x[y[i]]);
for (i=0;i<=mx;i++)Ws[i]=0;
for (i=0;i<n;i++)Ws[Wv[i]]++;
for (i=1;i<=mx;i++)Ws[i]+=Ws[i-1];
for (i=n-1;i>=0;i--)SA[--Ws[Wv[i]]]=y[i];
for (i=0;i<n;i++)y[i]=x[i],x[i]=0;
for (p=0,x[SA[0]]=0,i=1;i<n;i++)x[SA[i]]=cmp(y,SA[i-1],SA[i],l)?p:++p;
}
for (i=0;i<n;i++)rank[SA[i]]=i;
}
void get_height()
{
for (int k=0,i=0;i<n;i++)
{
k?k--:k;
if (!rank[i])
continue;
int j=SA[rank[i]-1];
while (i+k<n&&j+k<n&&s[i+k]==s[j+k])
k++;
height[rank[i]]=k;
}
}
int hashsum(int st,int en)
{
if (st>en)
return 0;
return (((LL)sum[en]-(st?sum[st-1]:0)-(LL)(st?hash[st-1]:0)*p[en-st]%P)%P+P)%P;
}
int prefixsum(int st,int en1,int en2)
{
return ((hashsum(st,en2)-hashsum(st,en1-1))%P+P)%P;
}
void calc()
{
int ptr=1,cnt=0;
LL kth=0,las=0;
for (int i=0;i<n;i++)
{
las=kth;
kth+=n-SA[i]-height[i];
while (ptr<=m<<1&&qu[ptr].K<=kth)
{
int j=qu[ptr].id,l=deal[j]?2:1;
deal[j]=1;
if (!qu[ptr].K)
ans[j][l]=0;
else
ans[j][l]=(cnt+prefixsum(SA[i],SA[i]+height[i],SA[i]+height[i]+qu[ptr].K-las-1))%P;
ptr++;
}
cnt=(cnt+prefixsum(SA[i],SA[i]+height[i],n-1))%P;
}
for (int i=1;i<=m;i++)
ans[i][0]=((ans[i][2]-ans[i][1])%P+P)%P;
}
int main()
{
freopen("hashsum.in","r",stdin);
freopen("hashsum.out","w",stdout);
scanf("%s",s);
n=strlen(s);
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%lld%lld",&q[i][0],&q[i][1]);
qu[(i<<1)-1].K=q[i][0]-1,qu[i<<1].K=q[i][1];
qu[(i<<1)-1].id=i,qu[i<<1].id=i;
}
sort(qu+1,qu+1+(m<<1));
pre();
DA();
get_height();
calc();
for (int i=1;i<=m;i++)
printf("%d\n",ans[i][0]);
fclose(stdin);
fclose(stdout);
return 0;
}