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

I Love Palindrome String


题意

给出字符串str

求出str中的子串数

且该子串为回文串并且该子串的前半串(包括中间字符)也为回文串


思路

  • 首先可以轻松预处理出所有本质不同回文串个数

    即使用回文自动机+常规操作

  • fail[]指针建树

  • fail树上DFS,在同一路径上的回文串为同一后缀的回文串

    DFS回溯维护不同长度回文串个数

  • 对于一个串,查询KaTeX parse error: Expected 'EOF', got '&' at position 28: …]>>1)+(len[now]&̲1)]是否存在即可

代码

回文自动机
void insert(char* in, int n) {
    len[0] = 0;len[1] = -1;		//回文自动机初始化
    fail[0] = 1;fail[1] = 1;
    num = 1;
    last = 0;
    for (int i = 1; i <= n; i++) {		//插入后端节点
        while (in[i - len[last] - 1] != in[i]) last = fail[last];
        if (!tree[last][in[i] - 'a']) {
            len[++num] = len[last] + 2;
            int j = fail[last];
            while (in[i - len[j] - 1] != in[i]) j = fail[j];
            fail[num] = tree[j][in[i] - 'a'];
            tree[last][in[i] - 'a'] = num;
            mark[num] = 0;
        }
        last = tree[last][in[i] - 'a'];
        mark[last]++;	//更新本质不同回文串个数
    }
    for (int i = num; i >= 0; i--)	//维护子树大小,即为该回文串个数
        mark[fail[i]] += mark[i];
}
fail
struct Edge {	//链式前向星
    int v;
    int next;
} edge[maxn];
int head[maxn], tot;
void AddEdge(int u, int v) {
    edge[++tot].v = v;
    edge[tot].next = head[u];
    head[u] = tot;
}
void build() {	//建树
    memset(head, 0, sizeof(int) * (num + 1));
    tot = 0;
    for (int i = 2; i <= num; i++) AddEdge(fail[i], i);
}
DFS
void dfs(int now) {
    vis[len[now]]++;	//标记已存在长度
    if (vis[(len[now] + 1) / 2] > 0) res[len[now]] += mark[now];
    //查询是否存在前缀为回文串
    for (int i = head[now]; i; i = edge[i].next)
        dfs(edge[i].v);
    vis[len[now]]--;	//回溯
    return;
}
void slove(int n) {
    memset(vis, 0, sizeof(int) * (n + 1));//初始化
    memset(res, 0, sizeof(int) * (n + 1));
    dfs(0);//dfs
    for (int i = 1; i < n; i++) printf("%d ", res[i]);
    printf("%d\n", res[n]);
}
AC
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 300010;
char in[maxn];
int g;
int tree[maxn][26];
int len[maxn], fail[maxn];
int mark[maxn];
int last, num;
void init() {
    memset(tree, 0, sizeof(tree));
}
void insert(char* in, int n) {
    len[0] = 0;
    len[1] = -1;
    fail[0] = 1;
    fail[1] = 1;
    num = 1;
    last = 0;
    for (int i = 1; i <= n; i++) {
        while (in[i - len[last] - 1] != in[i]) last = fail[last];
        if (!tree[last][in[i] - 'a']) {
            len[++num] = len[last] + 2;
            int j = fail[last];
            while (in[i - len[j] - 1] != in[i]) j = fail[j];
            fail[num] = tree[j][in[i] - 'a'];
            tree[last][in[i] - 'a'] = num;
            mark[num] = 0;
        }
        last = tree[last][in[i] - 'a'];
        mark[last]++;
    }
    for (int i = num; i >= 0; i--)
        mark[fail[i]] += mark[i];
}
struct Edge {
    int v;
    int next;
} edge[maxn];
int head[maxn], tot;
void AddEdge(int u, int v) {
    edge[++tot].v = v;
    edge[tot].next = head[u];
    head[u] = tot;
}
void build() {
    memset(head, 0, sizeof(int) * (num + 1));
    tot = 0;
    for (int i = 2; i <= num; i++) AddEdge(fail[i], i);
}
int vis[maxn];
int res[maxn];
void dfs(int now) {
    vis[len[now]]++;
    if (vis[(len[now] + 1) / 2] > 0) res[len[now]] += mark[now];
    for (int i = head[now]; i; i = edge[i].next)
        dfs(edge[i].v);
    vis[len[now]]--;
    return;
}
void slove(int n) {
    memset(vis, 0, sizeof(int) * (n + 1));
    memset(res, 0, sizeof(int) * (n + 1));
    dfs(0);
    for (int i = 1; i < n; i++) printf("%d ", res[i]);
    printf("%d\n", res[n]);
}
int main() {
    in[0] = '#';
    while (~scanf("%s", in + 1)) {
        init();
        int n = strlen(in + 1);
        insert(in, n);
        build();
        slove(n);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值