HDU6599多校第二场 I Love Palindrome String--回文树

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<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;
}
发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/97167638