You've got a string s = s1s2... s|s| of length |s|, consisting of lowercase English letters. There also are qqueries, each query is described by two integers li, ri (1 ≤ li ≤ ri ≤ |s|). The answer to the query is the number of substrings of string s[li... ri], which are palindromes.
String s[l... r] = slsl + 1... sr (1 ≤ l ≤ r ≤ |s|) is a substring of string s = s1s2... s|s|.
String t is called a palindrome, if it reads the same from left to right and from right to left. Formally, if t = t1t2... t|t| = t|t|t|t| - 1... t1.
The first line contains string s (1 ≤ |s| ≤ 5000). The second line contains a single integer q (1 ≤ q ≤ 106)— the number of queries. Next q lines contain the queries. The i-th of these lines contains two space-separated integers li, ri (1 ≤ li ≤ ri ≤ |s|) — the description of the i-th query.
It is guaranteed that the given string consists only of lowercase English letters.
Print q integers — the answers to the queries. Print the answers in the order, in which the queries are given in the input. Separate the printed numbers by whitespaces.
caaaba
5
1 1
1 4
2 3
4 6
4 5
1
7
3
4
2
Consider the fourth query in the first test case. String s[4... 6] = «aba». Its palindrome substrings are: «a», «b», «a», «aba».
大意:长度为N的字符串,Q个询问,询问某个区间中回文子串(连续)的数量
题解:
将字符串和反转串的RK hash值求出,这样可以O(1)判断两个子串是否相等。
f[i][j]表示[i,j]区间中回文子串的数量,可以以区间大小为阶段利用简单容斥来递推。
f[i][j]=f[i+1][j]+f[i][j-1]-f[i+1][j-1]+([i,j]是回文串)
要[i,j]是回文串,只需在原串中求出前半部分的 hash 值,在反转串中求出后半串的 hash 值,判断是否相等即可。
tips:亲测O(N^2 logN)过不了,要预处理seed的幂次方

1 /* 2 Welcome Hacking 3 Wish You High Rating 4 */ 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<ctime> 9 #include<cstdlib> 10 #include<algorithm> 11 #include<cmath> 12 #include<string> 13 using namespace std; 14 int read(){ 15 int xx=0,ff=1;char ch=getchar(); 16 while(ch>'9'||ch<'0'){if(ch=='-')ff=-1;ch=getchar();} 17 while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();} 18 return xx*ff; 19 } 20 const int seed[2]={13137,91},MOD=1000000007; 21 char s1[5010],s2[5010]; 22 int H1[2][5010],H2[2][5010]; 23 int N; 24 int pow_seed[2][5010]; 25 void Hashing(int x){ 26 for(int i=1;i<=N;i++){ 27 H1[x][i]=(1LL*H1[x][i-1]*seed[x]+s1[i])%MOD; 28 H2[x][i]=(1LL*H2[x][i-1]*seed[x]+s2[i])%MOD; 29 } 30 } 31 int get_hash1(int x,int L,int R){ 32 return ((H1[x][R]-1LL*H1[x][L-1]*pow_seed[x][R-L+1])%MOD+MOD)%MOD; 33 } 34 int get_hash2(int x,int L,int R){ 35 return ((H2[x][R]-1LL*H2[x][L-1]*pow_seed[x][R-L+1])%MOD+MOD)%MOD; 36 } 37 inline int ref(int x) 38 {return N-x+1;} 39 inline bool judge(int L,int R){ 40 if(L==R) 41 return 1; 42 int mid=(L+R)/2; 43 if((R-L+1)%2==0){ 44 if(get_hash1(0,L,mid)==get_hash2(0,ref(R),ref(mid+1))) 45 if(get_hash1(1,L,mid)==get_hash2(1,ref(R),ref(mid+1))) 46 return 1; 47 } 48 else{ 49 if(get_hash1(0,L,mid)==get_hash2(0,ref(R),ref(mid))) 50 if(get_hash1(1,L,mid)==get_hash2(1,ref(R),ref(mid))) 51 return 1; 52 } 53 return 0; 54 } 55 long long f[5010][5010]; 56 int main(){ 57 //freopen("in","r",stdin); 58 gets(s1+1);N=strlen(s1+1); 59 for(int i=1;i<=N;i++) 60 s2[i]=s1[ref(i)]; 61 pow_seed[0][0]=pow_seed[1][0]=1; 62 for(int i=1;i<=N;i++){ 63 pow_seed[0][i]=1LL*pow_seed[0][i-1]*seed[0]%MOD; 64 pow_seed[1][i]=1LL*pow_seed[1][i-1]*seed[1]%MOD; 65 } 66 Hashing(0); 67 Hashing(1); 68 for(int i=1;i<=N;i++) 69 f[i][i]=1; 70 for(int p=2;p<=N;p++) 71 for(int i=1;i<=N;i++){ 72 int j=i+p-1; 73 if(j>N) 74 break; 75 f[i][j]=f[i+1][j]+f[i][j-1]-f[i+1][j-1]+judge(i,j); 76 } 77 /*for(int i=1;i<=N;i++){ 78 for(int j=1;j<=N;j++) 79 printf("%I64d ",f[i][j]); 80 puts(""); 81 }*/ 82 for(int Q=read();Q;Q--){ 83 int t1=read(),t2=read(); 84 printf("%I64d ",f[t1][t2]); 85 } 86 return 0; 87 }