Description
You are given a non-empty string s consisting of lowercase letters. Find the number of pairs of non-overlapping palindromic substrings of this string.
In a more formal way, you have to find the quantity of tuples (a, b, x, y) such that 1 ≤ a ≤ b < x ≤ y ≤ |s| and substrings s[a… b], s[x… y] are palindromes.
A palindrome is a string that can be read the same way from left to right and from right to left. For example, “abacaba”, “z”, “abba” are palindromes.
A substring s[i… j] (1 ≤ i ≤ j ≤ |s|) of string
s
=
s
1
s
2
.
.
.
s
∣
s
∣
s = s_1 s_2... s_|s|
s=s1s2...s∣s∣ is a string
s
i
s
i
+
1
.
.
.
s
j
s_i s_{i + 1}... s_j
sisi + 1...sj. For example, substring
s
[
2...4
]
s[2...4]
s[2...4] of string s = “abacaba” equals “bac”.
Input
The first line of input contains a non-empty string s which consists of lowercase letters (‘a’…‘z’), s contains at most 2000 characters.
Output
Output a single number — the quantity of pairs of non-overlapping palindromic substrings of s.
Please do not use the %lld format specifier to read or write 64-bit integers in С++. It is preferred to use cin, cout streams or the %I64d format specifier.
Examples
Input
aa
Output
1
Input
aaa
Output
5
Input
abacaba
Output
36
Main idea & Solution
给你一个串,让你找出有多少对不相交的子串s1,s2,满足s1 和 s2 都是回文串
注意到对于当前回文串
{
l
,
r
}
\left\{l,r\right\}
{l,r},
[
1
,
l
−
1
]
[1, l - 1]
[1,l−1] 以内的所有回文串都可以和它组成合法答案
我们先用Manacher预处理,再计算
d
p
[
i
]
dp[i]
dp[i] : 以
i
i
i 为结尾的回文子串数,并计算该数组的前缀和
最后枚举计算答案即可
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 5;
char s[maxn];
int p[maxn*2];
char Ma[maxn*2];
void Manacher(int len){
int l = 0;
Ma[l++] = '$';Ma[l++] = '#';
for(int i = 0;i < len;++i){
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = 0;
int mx = 0, id = 0;
for(int i = 0;i < l;++i){
p[i] = mx > i ? min(p[id*2-i],mx-i) : 1;
while(Ma[i+p[i]] == Ma[i-p[i]]) p[i]++;
if(i + p[i] > mx){
mx = i + p[i];
id = i;
}
}
}
int dp[maxn*2];
int main(){
ll res = 0;
scanf("%s",s);
int n = strlen(s);
Manacher(n);
for(int i = 1;i <= 2 * n;++i){
int d = p[i];
for(int j = 0 + (i&1);j < d;j+=2){
dp[i+j]++;
}
}
dp[0] = 0;
for(int i = 1;i <= 2 * n;++i){
dp[i] += dp[i-1];
}
for(int i = 1;i <= 2 * n;++i){
int d = p[i];
for(int j = 0 + (i&1);j < d;j+=2){
res += dp[i-j-1];
}
}
printf("%lld\n", res);
return 0;
}