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("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/isakovsky/p/11259044.html