dp
用 f[i][j] 表示 i 到 j 之间最长的头尾回文串的长度,那么如果 a[i]==a[j] ,那么 f[i][j] = f[i+1][j-1]+1,否则f[i][j] = 0。注意如果 f[i+1][j-1] 的回文长度等于它本身的长度,那么f[i][j] = f[i+1][j-1]+2。这个式子可以自己画图看一下。小细节就是这里的枚举顺序要从短到长进行枚举。最后用树状数组或者前缀和进行统计就可以了。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 5010;
int f[maxn][maxn];
char s[maxn];
ll g[maxn];
int n;
void insert(int x) {
while (x > 0) {
g[x]++;
x = x-(x & (-x));
}
}
ll find(int x) {
ll t = 0;
while (x < maxn) {
t += g[x];
x = x+(x & (-x));
}
return t;
}
int main() {
///freopen("input.txt","r",stdin);
scanf("%s", s+1);
n = strlen(s+1);
for (int i = 1; i <= n; i++) f[i][i] = 1;
for (int k = 2; k <= n; k++) {
for (int i = 1; i+k-1 <= n; i++) {
int j = i+k-1;
if (s[i] != s[j]) {
f[i][j] = 0;
} else {
f[i][j] = f[i+1][j-1]+1;
ll t = f[i][j];
while (i+t-1 < j && s[i+t] == s[j-t]) t++;
f[i][j] = t;
}
}
}
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) {
insert(f[i][j]);
}
for (int i = 1; i <= n; i++) {
if (i > 1) printf(" ");
printf("%lld", find(i));
}
}