Harry and magic string
Problem Description
Harry got a string T, he wanted to know the number of T’s disjoint palindrome substring pairs. A string is considered to be palindrome if and only if it reads the same backward or forward. For two substrings of T T T: x = T [ a 1 … b 1 ] x=T[a_1…b_1] x=T[a1…b1], y = T [ a 2 … b 2 ] y=T[a_2…b_2] y=T[a2…b2](where a 1 a_1 a1 is the beginning index of x, b 1 b_1 b1 is the ending index of x. a 2 a_2 a2, b 2 b_2 b2 as the same of y), if both x and y are palindromes and b 1 < a 2 b_1<a_2 b1<a2 or b 2 < a 1 b_2<a_1 b2<a1 then we consider ( x , y ) (x, y) (x,y) to be a disjoint palindrome substring pair of T.
Input
There are several cases.
For each test case, there is a string T in the first line, which is composed by lowercase characters. The length of T is in the range of [1,100000].
Output
For each test case, output one number in a line, indecates the answer.
Sample Input
aca
aaaa
Sample Output
3
15
题意
求字符串中不相交的回文子串的点对数。
题解:
对于每个位置
i
i
i,求出以它为结束位置和以它为起始位置的回文子串的数量,分别即为
a
i
a_i
ai,
b
i
b_i
bi。
对于每个点对,已知以
i
i
i为起始位置的回文子串有
b
i
b_i
bi个,则回文点对有
(
a
1
+
a
2
+
.
.
+
a
i
−
1
)
∗
b
i
(a_1+a_2+..+a_{i-1})*b_i
(a1+a2+..+ai−1)∗bi个。
求出所有i的和即可。
b
i
b_i
bi可以通过反向建回文树求得。
a
1
+
a
2
+
.
.
+
a
i
−
1
a_1+a_2+..+a_{i-1}
a1+a2+..+ai−1可以通过前缀和计算。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 200010;
const int mod = 1000000007;
struct node{
int len, fail, cnt, num, nex[26];
}st[maxn];
int cnt, last, len, c[maxn], b[maxn];
LL sum[maxn];
char str[maxn], s[maxn];
void init();
int creat(int x);
int getfail(int x);
int Insert(char ch);
int main()
{
int n, i, j, k;
while(~scanf("%s", str+1))
{
LL ans = 0;
n = strlen(str+1);
init();
sum[0] = 0;
for(i=1;i<=n;i++){
b[i] = Insert(str[i]);
sum[i] = sum[i-1] + b[i];
}
init();
for(i=n;i>=1;i--){
c[i] = Insert(str[i]);
ans += c[i]*sum[i-1];
}
printf("%lld\n", ans);
}
return 0;
}
void init()
{
cnt = -1;
last = len = 0;
str[0] = '*';
creat(0);
creat(-1);
st[0].fail = 1;
}
int creat(int x)
{
cnt++;
st[cnt].len = x;
memset(st[cnt].nex, 0, sizeof(st[cnt].nex));
st[cnt].cnt = st[cnt].num = 0;
st[cnt].fail = 0;
return cnt;
}
int getfail(int x)
{
while(s[len-st[x].len-1] != s[len]) x = st[x].fail;
return x;
}
int Insert(char ch)
{
s[++len] = ch;
int cur = getfail(last);
if(!st[cur].nex[ch-'a']){
int now = creat(st[cur].len + 2);
st[now].fail = st[getfail(st[cur].fail)].nex[ch-'a'];
st[cur].nex[ch-'a'] = now;
st[now].num = st[st[now].fail].num + 1;
}
last = st[cur].nex[ch-'a'];
st[last].cnt++;
return st[last].num;
}