因为只有20,所以我们按长度建可持久化字典树,然后询问时枚举长度即可,长度为奇数和偶数可以分开求。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=100105;
int root[2][10][maxn];
int cnt;
namespace Trie{
int sum[maxn*20];
int ch[maxn*20][5];
void init(){
cnt=0;
memset(root,0,sizeof(root));
memset(ch[0],0,sizeof(ch[0]));
sum[0]=0;
}
void insert(int pre,int no,char *t){
int p=strlen(t);
for(int i=0;i<p;i++){
for(int j=0;j<5;j++){
ch[no][j]=ch[pre][j];
}
int w=t[i]-'a';
ch[no][w]=++cnt;
no=ch[no][w];
pre=ch[pre][w];
sum[no]=sum[pre]+1;
}
for(int j=0;j<5;j++){
ch[no][j]=ch[pre][j];
}
}
int query(int pre,int no,char *t){
int p=strlen(t);
int flag=0;
for(int i=0;i<p;i++){
pre=ch[pre][t[i]-'a'];
no=ch[no][t[i]-'a'];
if(no==0) return 0;
if(pre==0){
flag=1;
}
}
if(flag) return sum[no];
return sum[no]-sum[pre];
}
}
char s[maxn];
char t[20];
int main()
{
while(scanf("%s",s)!=EOF){
Trie::init();
int n;
n=strlen(s);
for(int j=n;j>=1;j--) s[j]=s[j-1];
for(int i=1;i<=10;i++){
for(int j=i;j+i-1<=n;j++){
int flag=0;
for(int f=j;f<=j+i-1;f++){
if(s[f]!=s[2*j-f]){
flag=1;
break;
}
t[f-j]=s[f];
}
t[i]='\0';
if(flag==0){
root[0][i-1][j]=++cnt;
Trie::insert(root[0][i-1][j-1],cnt,t);
}
else{
root[0][i-1][j]=root[0][i-1][j-1];
}
}
for(int j=i+1;j+i-1<=n;j++){
int flag=0;
for(int f=j;f<=j+i-1;f++){
if(s[f]!=s[2*j-f-1]){
flag=1;
break;
}
t[f-j]=s[f];
}
t[i]='\0';
if(flag==0){
root[1][i-1][j]=++cnt;
Trie::insert(root[1][i-1][j-1],cnt,t);
}
else{
root[1][i-1][j]=root[1][i-1][j-1];
}
}
}
int m;
scanf("%d",&m);
for(int i=0;i<m;i++){
int l,r;
scanf("%d%d",&l,&r);
scanf("%s",t);
int ans=0;
for(int j=1;j<=min((r-l+2)/2,10);j++){
int x=l+j-1;
int y=r-j+1;
if(x<=y){
ans+=Trie::query(root[0][j-1][x-1],root[0][j-1][y],t);
}
if(x<y){
ans+=Trie::query(root[1][j-1][x],root[1][j-1][y],t);
}
}
printf("%d\n",ans);
}
}
}