先上题目:
You've got a string s = s1s2... s|s| of length |s|, consisting of lowercase English letters. There also are q queries, 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».
题意:给你一个字符串,q个查询,问你某个区间里面有多少个回文串。
区间dp,需要三个数组: s[] 字符串;f[i][j] [i,j]是不是一个回文串;dp[i][j] [i,j]包含了多少个字符串。
初始化:
f[i][i]=1
f[i][i-1]=1 //在判断偶数长度的回文串的时候需要使用
dp[i][i]=1
状态转移方程: dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+f[i][j]
为什么可以这样列方程?这需要说一下对字符串的操作:我们先判断短的字符串,然后再增长判断的长度,这样dp[i+1][j]、dp[i][j-1]和dp[i+1][j-1]在对dp[i][j]操作之前就已经处理完保存了处理以后的数据了。
上代码:
1 #include <cstdio> 2 #include <cstring> 3 #define MAX 5002 4 using namespace std; 5 6 char s[MAX]; 7 8 /* 9 dp[i][j]: [i,j]中包含了多少个回文串 10 f[i][j]: [i,j]是否是回文串 11 */ 12 int dp[MAX][MAX]; 13 int f[MAX][MAX]; 14 15 int main() 16 { 17 int q,a,b,l; 18 //freopen("data.txt","r",stdin); 19 while(scanf("%s",s+1)!=EOF){ 20 memset(dp,0,sizeof(dp)); 21 memset(f,0,sizeof(f)); 22 l=strlen(s+1); 23 for(int i=1;i<=l;i++){ 24 /*初始化: 25 f[i][i]=1 单个字母是一个回文串 26 f[i][i-1]=1 考虑偶数个字母是一个回文串的时候的情况(状态转移的方向决定的) 27 dp[i][i]=1 单个字母的时候[i,i]有一个回文串 28 */ 29 f[i][i]=1; 30 f[i][i-1]=1; 31 dp[i][i]=1; 32 } 33 for(int le=2;le<=l;le++){ 34 for(int i=1,j=le;j<=l;i++,j++){ 35 if(s[i]==s[j]){ 36 /*s[i]==s[j] && [i+1,j-1]也是回文串*/ 37 f[i][j]=f[i+1][j-1]; 38 } 39 dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+f[i][j]; 40 } 41 } 42 scanf("%d",&q); 43 while(q--){ 44 scanf("%d %d",&a,&b); 45 printf("%d ",dp[a][b]); 46 } 47 48 } 49 return 0; 50 }