hdu 6599 I Love Palindrome String(回文自动机)

题目链接

题意

给定一个长度为$n$的字符串,对于$1<=i<=n$,求满足长度为$i$,本身是回文串并且它的前一半也是回文串的子串个数。

题解

  • 对于求长度为$x$的回文子串个数的问题可以用回文自动机在线性时间复杂度内解决。
  • 但此题要求回文子串的前一半也是回文串,显然前一半是回文串等价于后一半也是回文串,那么我们可以在构建回文自动机的同时维护一个$half$数组,表示不超过当前回文串的长度的一半的最长回文后缀
  • 构建half数组与fail数组类似,从当前节点fail指针指向节点的half数组转移过来即可
查看代码
#include <stdio.h>
#include <string.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i <= (b); ++i)
typedef long long ll;
const int maxn = 3e5 + 5;
const int mod = 1e9 + 7;
struct PAM
{
    int len[maxn], fail[maxn], ch[maxn][26], cnt[maxn], tot, last, p, q;
    int half[maxn], ans[maxn], n;
    char s[maxn];
    void init()
    {
        s[0] = -1, fail[0] = 1, fail[1] = 0;
        len[0] = 0, len[1] = -1, tot = 1;
        last = 0;
        for (int i = 0; i <= n + 3; ++i)
        {
            cnt[i] = ans[i] = half[i] = 0;
            for (int j = 0; j < 26; ++j)
                ch[i][j] = 0;
        }
    }
    int newnode(int x)
    {
        len[++tot] = x;
        return tot;
    }
    int getfail(int x, int n)
    {
        while (s[n - len[x] - 1] != s[n])
            x = fail[x];
        return x;
    }
    void build()
    {
        for (int i = 1; s[i]; ++i)
        {
            s[i] -= 'a';
            p = getfail(last, i);
            if (!ch[p][s[i]])
            {
                q = newnode(len[p] + 2);
                fail[q] = ch[getfail(fail[p], i)][s[i]];
                ch[p][s[i]] = q;
                if (len[q] <= 2)
                    half[q] = fail[q];
                else
                {
                    int tmp = half[p];
                    while (s[i - len[tmp] - 1] != s[i] || (len[tmp] + 2) * 2 > len[q] + 1)
                        tmp = fail[tmp];
                    half[q] = ch[tmp][s[i]];
                }
            }
            ++cnt[last = ch[p][s[i]]];
        }
    }
    void cal()
    {
        for (int i = tot; i >= 0; --i)
        {
            cnt[fail[i]] += cnt[i];
            if (len[half[i]] == (len[i] + 1) / 2 || len[i] == 1)
                ans[len[i]] += cnt[i];
        }
        for (int i = 1; i < n; ++i)
        {
            printf("%d ", ans[i]);
        }
        printf("%d\n",ans[n]);
    }
} pam;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("simple.in", "r", stdin);
    freopen("simple.out", "w", stdout);
#endif
    while (~scanf("%s", pam.s + 1))
    {
        pam.n = strlen(pam.s + 1);
        pam.init();
        pam.build();
        pam.cal();
    }
    return 0;
}
posted @ 2020-06-03 15:17  tryatry  阅读(110)  评论(0编辑  收藏  举报