Solution
建出回文自动机,每个节点再维护一个
halfu
指针,指向长度不超过
⌊lenu2⌋
的最长回文后缀。
树形DP出每个点的
ness
表示回文指数,答案就是
∑nessu∗|rightu|
。
fail
链上的节点的
lenv
一定是递减的。可以倍增。
设
u
在后缀自动机上的父亲为
口胡一波复杂度
设势能函数
Φ(s)
等于字符串
s
的不超过
啊膜改了论文里的回文自动机的复杂度分析。
#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> Pairs;
const int N = 101010;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0; int sgn = 0;
for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
if (sgn) x = -x;
}
inline void read(char *s) {
static char c; int len = 0;
for (c = get(); c < 'a' || c > 'z'; c = get());
for (; c >= 'a' && c <= 'z'; c = get()) s[len++] = c;
s[len] = 0;
}
int ch[N][30];
int par[N], len[N];
int rgt[N], half[N], ness[N];
int last, Tcnt;
int n, test;
long long ans;
char s[N];
inline void Init(void) {
memset(ch, 0, sizeof ch);
memset(rgt, 0, sizeof rgt);
memset(half, 0, sizeof half);
par[0] = par[1] = 1;
half[0] = half[1] = 1;
len[1] = -1;
Tcnt = 1; last = 0;
}
inline void Extend(int pos) {
int p = last, key = s[pos];
while (s[pos - len[p] - 1] != key) p = par[p];
if (!ch[p][key]) {
int np = ++Tcnt, q = par[p];
len[np] = len[p] + 2;
while (s[pos - len[q] - 1] != key) q = par[q];
par[np] = ch[q][key]; q = half[p];
while (len[ch[q][key]] > len[np] / 2 || s[pos - len[q] - 1] != key) q = par[q];
half[np] = ch[q][key];
ch[p][key] = np;
}
last = ch[p][key]; ++rgt[last];
}
int main(void) {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
read(test);
while (test--) {
read(s + 1); s[0] = -1;
n = strlen(s + 1); Init();
for (int i = 1; i <= n; i++) {
s[i] -= 'a'; Extend(i);
}
for (int i = 2; i <= Tcnt; i++)
if (len[half[i]] == len[i] / 2)
ness[i] = 1 + ness[half[i]];
else ness[i] = 1;
ans = 0;
for (int i = Tcnt; ~i; i--) {
rgt[par[i]] += rgt[i];
ans += (long long)ness[i] * rgt[i];
}
cout << ans << endl;
}
return 0;
}