http://acm.hdu.edu.cn/showproblem.php?pid=6599
题意:给你一个字符串,然后叫你求,对于每一个长度i-len,问有多少个,回文串的前一半也是回文串。
首先,简单说一下回文树,又称为回文自动机,他是一种类似与Trie的数据结构,你插入一个字符串,他经过处理可以得到一个字符串本质不同的回文串的数量以及长度,是十分方便,同时还可以经过膜改,可以得到很多信息,例如第一次出现那一个本质不同的回文串的位置等等。
做法:以前只看过回文树的板子,根本就没有深入学习,这次终于遇到了,首先应用回文树,求得本质不同的回文串,同时得到他的数量与长度,然后对于每一个回文串的长度,在判断他的前面部分是不是回文串,因为他本身是回文串,因此就是判断前后两部分是否相同,这个可以用manacher,或者字符串哈希,个人觉得哈希简单一点。
这里回文树的作用就是求得每一个本质不同的回文串的个数与数量,同时用一个数组标记,回文串末尾的位置。
关于回文树给一篇大佬的博客这里
#include "bits/stdc++.h"
using namespace std;
const double eps = 1e-8;
#define reg register
#define lowbit(x) x&-x
#define pll pair
#define pii pair
#define fi first
#define se second
#define makp make_pair
int dcmp(double x) {
if (fabs(x) < eps) return 0;
return (x > 0) ? 1 : -1;
}
typedef long long ll;
typedef unsigned long long ull;
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const int N = 300000 + 10;
const int M = 1000 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
ll ret[N];
ull ha[N], pp[N];
ull getha(int l, int r) {
if (l == 0) return ha[r];
return ha[r] - ha[l - 1] * pp[r - l + 1];
}
bool check(int l, int r) {
int len = r - l + 1;
int mid = (l + r) >> 1;
if (len & 1) return getha(l, mid) == getha(mid, r);
else return getha(l, mid) == getha(mid + 1, r);
}
struct Palindromic_Tree {
int nxt[N][30], fail[N], cnt[N];
int num[N], len[N], s[N], id[N];
int last, n, p;
int newnode(int l) {
memset(nxt[p], 0, sizeof(nxt[p]));
cnt[p] = num[p] = 0;
len[p] = l;
return p++;
}
void init() {
p = 0;
newnode(0), newnode(-1);
last = n = 0;
s[0] = -1;
fail[0] = 1;
}
int get_fail(int x) {
while (s[n - len[x] - 1] != s[n]) x = fail[x];
return x;
}
void add(int c) {
c -= 'a';
s[++n] = c;
int cur = get_fail(last);
if (!nxt[cur][c]) {
int now = newnode(len[cur] + 2);
fail[now] = nxt[get_fail(fail[cur])][c];
nxt[cur][c] = now;
num[now] = num[fail[now]] + 1;
}
last = nxt[cur][c];
cnt[last]++, id[last] = n;
}
ll Count() {
for (int i = p - 1; i >= 0; i--) cnt[fail[i]] += cnt[i];
for (int i = 2; i < p; i++) {
///cout << id[i] - len[i] << " " << id[i] - 1 << endl;
if (check(id[i] - len[i], id[i] - 1)) {
ret[len[i]] += cnt[i];
}
}
return 0;
}
} pam;
char str[N];
int main() {
pp[0] = 1;
for (int i = 1; i < N; i++) {
pp[i] = hash1 * pp[i - 1];
}
while (~scanf("%s", str)) {
memset(ret, 0, sizeof(ret));
pam.init();
int len = strlen(str);
ha[0] = str[0];
for (int i = 0; i < len; i++) {
pam.add(str[i]);
}
for (int i = 1; i < len; i++) {
ha[i] = ha[i - 1] * hash1 + str[i];
}
pam.Count();
printf("%lld", ret[1]);
for (int i = 2; i <= len; i++) {
printf(" %lld", ret[i]);
}
printf("\n");
}
return 0;
}