MYF

Cyw的回文串

题目链接

解题方法:DP

题目分析

题目

Description

Cyw有一个长度为n的字符串s(字符串只包小写字母)。现在有一些询问,对于给定的区间l,r,他想知道在区间[l,r]中共有多少个回文子串。(字符串下标从1开始,n≤1000)

Input

第一行有一个整数T(T≤30),表示数据组数。
接下来有T组数据。
对于每一组数据,第一行输入字符串s,第二行输入一个整数q(q≤1000000),表示询问次数。接下来q行,每行两个整数li,ri,表示询问的区间为[li,ri]。保证询问数据合法(1≤li≤ri≤n)

Output

输出有q行,每行只有一个整数,表示每个询问的结果。

Sample Input

 1
 caaaba
 5
 1 1
 1 4
 2 3
 4 6
 4 5
 

Sample Output

 1
 7
 3
 4
 2
 

解析

本题使用了两次DP,一个是处理回文串的时候使用了一次,一个是遍历下标的时候使用了一次,查询的时候效率是o(1)。感觉这题难度不错,适合DP入门。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <limits>
#include <iostream>
#include <algorithm>
#define PI acos(-1)
#define debug printf("Hi----------\n")
#define eps 1e-8
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long ll;
using namespace std;
#define maxn 10005
int dp[1005][1005];
int mp[1005][1005];
int main(){
int t,l,r,m;
scanf("%d",&t);
char s[1005];
while (t--) {
scanf("%s",s+1);
int len=strlen(s+1);
memset(dp, 0, sizeof(dp));
memset(mp, 0, sizeof(mp));

for (int i=1; i<=len; i++) {
mp[i][i]=1;
if (i>1&&s[i]==s[i-1]) {
mp[i-1][i]=1;
}
}

for (int i=2; i<len; i++) {
for (int j=1; j+i<=len; j++) {
if (s[j]==s[j+i]&&mp[j+1][j+i-1]==1) {
mp[j][j+i]=1;
}
}
}


for (int i=1; i<=len; i++) {
dp[i][i]=1;
}

for (int i=1; i<len; i++) {
for (int j=1; j+i<=len; j++) {
dp[j][j+i]=dp[j][j+i-1]+dp[j+1][j+i]+mp[j][j+i]-dp[j+1][j+i-1];
}
}

scanf("%d",&m);
while (m--) {
scanf("%d%d",&l,&r);
printf("%d\n",dp[l][r]);
}
}
}