给一个长度为n的字符串,找三元组(i,j,k)的个数满足s[i..j]是一个回文串,s[j+1..k]是一个回文串。( i≤j<k ).
样例的abaa的三元组有
(1,1,2)
(1,3,4)
(2,2,3)
(2,3,4)
(3,3,4)
和SHOI的那个双倍回文差不多。
找出所有的极长回文子串后,指针i正反扫2次,统计满足
j+pj−1≥i
或
j−pj+1≤i
的j的个数,因为i是单调增/减的,所以左边那块可以用set维护。
没开long long WA了一发。。
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
const int N = 610000;
char s[N]; int p[N], a[N], c[N], d[N];
multiset<int> S;
int main() {
int i, n, m, mx = 0, id;
long long ans = 0;
scanf("%s", s + 1);
n = strlen(s + 1); m = 2 * n + 1;
for (i = 1; i <= n; ++i) {
a[i * 2] = s[i];
a[i * 2 + 1] = '$';
}
a[0] = '+'; a[m + 1] = '-'; a[1] = '$';
for (i = 1; i <= m; ++i) {
if (mx > i) p[i] = min(mx - i, p[2 * id - i]);
else p[i] = 1;
for (; a[i - p[i]] == a[i + p[i]]; ++p[i]);
if (i + p[i] > mx) mx = i + p[i], id = i;
}
set<int>::iterator it;
for (i = 1; i <= m; ++i) {
S.insert(i + p[i] - 1);
while (*(it = S.begin()) < i)
S.erase(it);
c[i] = S.size();
}
S.clear();
for (i = m; i; --i) {
S.insert(i - p[i] + 1);
while (*(--(it = S.end())) > i) S.erase(it);
d[i] = S.size();
}
for (i = 2; i < m; i += 2) ans += 1ll * c[i] * d[i + 2];
printf("%lld", ans);
return 0;
}
2060. Subpalindrome pairs
Your task is to calculate number of triplets (i, j, k) such that i ≤ j < k and s[i..j] is a palindrome and s[j+1 .. k] is a palindrome.
Input
The input contains a line of n lowercase Latin letters (1 ≤ n ≤ 3 · 105).
Output
Output the answer.
Sample
input
abaa
output
5