Queries for Number of Palindromes
我们可以设
d
p
[
l
]
[
r
]
dp[l][r]
dp[l][r] 为
[
l
,
r
]
[l,r]
[l,r] 中 的答案。那么我们可以找到转移方程:
d
p
[
l
]
[
r
]
=
d
p
[
l
+
1
]
[
r
]
+
d
p
[
l
]
[
r
−
1
]
−
d
p
[
l
+
1
]
[
r
−
1
]
+
c
h
e
c
k
(
l
,
r
)
(
判
断
整
个
[
l
,
r
]
是
不
是
回
文
串
)
dp[l][r] = dp[l+1][r]+dp[l][r-1]-dp[l+1][r-1]+check(l,r) (判断整个[l,r]是不是回文串)
dp[l][r]=dp[l+1][r]+dp[l][r−1]−dp[l+1][r−1]+check(l,r)(判断整个[l,r]是不是回文串)
那么关键就是判断一个串是否是回文串,也就是实现上面的 c h e c k ( l , r ) check(l,r) check(l,r) 。那么我们可以对字符串正反哈希两遍求得,然后我们就可以愉快的进行区间 d p dp dp 了。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 10;
typedef unsigned long long ull;
int n, dp[N][N];
char s[N];
ull zhs[N], fhs[N], base = 233, b[N];
ull L(int l, int r) {return l > r ? 0 : zhs[r] - zhs[l - 1] * b[r - l + 1];}
ull R(int tl, int tr) {int l = n - tr + 1, r = n - tl + 1; return l > r ? 0 : fhs[r] - fhs[l - 1] * b[r - l + 1];}
void init() {
b[0] = 1;
for (int i = 1; i <= n; ++i) b[i] = b[i - 1] * base;
for (int i = 1; i <= n; ++i) zhs[i] = zhs[i - 1] * base + s[i];
reverse(s + 1, s + 1 + n);
for (int i = 1; i <= n; ++i) fhs[i] = fhs[i - 1] * base + s[i];
}
bool check(int l, int r) {
int mid = l + r >> 1;
if ((r - l + 1) & 1) {
return L(l, mid - 1) == R(mid + 1, r);
}
return L(l, mid) == R(mid + 1, r);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%s", (s + 1));
n = strlen(s + 1);
init();
for (int len = 1; len <= n; ++len) {
for (int l = 1, r; l + len - 1 <= n; ++l) {
r = l + len - 1;
dp[l][r] = dp[l + 1][r] + dp[l][r - 1] - dp[l + 1][r - 1] + check(l, r);
}
}
int q; scanf("%d", &q);
while(q--) {
int l, r; scanf("%d%d", &l, &r);
printf("%d\n", dp[l][r]);
}
}