hdu多校第二场1009 (hdu6599) I Love Palindrome String 回文自动机/字符串hash
题意:
找出这样的回文子串的个数:它本身是一个回文串,它的前一半也是一个回文串
输出格式要求输出l个数字,分别代表长度为1~l的这样的回文串的个数
题解:
(回文自动机和回文树是一个东西)
首先用回文自动机求出所有本质不同的字符串,以及它们出现的次数,把前半部分的字符串和后半部分的字符串分别hash一遍,看他们是不是相等。
构造好回文自动机后,在回文自动机上dfs,向下传递当前字符串长度,正向,反向hash值,每次递归因为只增加了一个字母,所以可以O(1)计算。
#include "bits/stdc++.h" using namespace std; const double eps = 1e-8; #define reg register #define lowbit(x) x&-x #define pll pair<ll,ll> #define pii pair<int,int> #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; }