http://acm.hdu.edu.cn/showproblem.php?pid=6599

有好几种实现方式,首先都是用回文自动机统计好回文串的个数。

记得把每个节点的cnt加到他的fail上,因为他既然出现了那么他的fail也当然会出现。

这里需要一直从fail向上找到一个长度恰好一半的节点,这也是TLE的来源,重复跳了大量的指针。dalao给了一种实现。

额外维护一个x数组,假如x[i]==0,说明还没人动过它,x[i]=i。

然后沿着fail把x[i]向上移动到第一个>=它的长度的一半的fail祖先,验证是不是长度恰好一半。

最后把i的fail父亲的x指针指向x[i],也就是把它的fail父亲直接x指向i的fail祖先,这样它父亲就不需要经过一系列没有用的fail转移了。

这个是个“不那么彻底的”路径压缩。源于一个点s的fail父f,f需要用的fail祖先必定是s的祖先,s可以每次把它父亲f一起给移动了。

当然也有hash大法、manacher大法。

hash大法好!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; struct Node {
int len, ch[26], fail;
ll cnt, x, y;
//string str;
Node(int len = 0) : len(len), fail(0) {
memset(ch, 0, sizeof(ch));
//下面是维护额外信息
cnt = 0;
x = 0;
y = 0;
//str = "";
}
/*void show() {
printf(" str=\"%s\"\n", str.c_str());
printf(" len=%d cnt=%d\n", len, cnt);
}*/
}; const int MAXN = 300000; ll ans2[MAXN + 5]; //PalindromicAutomaton
struct PAM {
Node nd[MAXN + 5]; int len, top, last; // len为字符串长度mtop为节点个数,last为最后插入字符所对应的节点
char s[MAXN + 5];
//string ls; //用来展示的辅助字符串 int getfail(int x) { //沿着fail指针找到第一个回文后缀
while(s[len - nd[x].len - 1] != s[len])
x = nd[x].fail;
return x;
} void init() {
len = 0, top = 0, last = 0;
nd[top] = Node(0);
nd[top].fail = 1;
nd[++top] = Node(-1);
nd[top].fail = 0;
s[0] = '$';
} void extend(char c) {
s[++len] = c;
int now = getfail(last); //找到插入的位置
//ls = nd[now].str + c; //用来展示的辅助字符串
if(!nd[now].ch[c - 'a']) { //若没有这个节点,则新建并求出它的fail指针
nd[++top] = Node(nd[now].len + 2);
nd[top].fail = nd[getfail(nd[now].fail)].ch[c - 'a'];
nd[now].ch[c - 'a'] = top;
}
last = nd[now].ch[c - 'a'];
//nd[last].str = ls; //用来展示的辅助字符串
//下面是维护额外信息
++nd[last].cnt;
} /*void show() {
for(int i = top; i >= 0; --i) {
printf("node: id=%d\n", i);
nd[i].show();
printf("fail: id=%d\n", nd[i].fail);
nd[nd[i].fail].show();
puts("");
}
}*/ void count() {
for(int i = top; i >= 2; --i)
nd[nd[i].fail].cnt += nd[i].cnt;
} void solve() {
for(int i = top; i >= 2; --i) {
if(nd[i].x == 0)
nd[i].x = i;
while(nd[nd[i].x].len > (nd[i].len + 1) / 2 )
nd[i].x = nd[nd[i].x].fail;
if(nd[nd[i].x].len == (nd[i].len + 1) / 2)
nd[i].y = 1;
nd[nd[i].fail].x = nd[i].x;
}
} void ans(int n) {
memset(ans2, 0, sizeof(ans2[1]) * (n + 1));
for(int i = top; i >= 2; --i) {
ans2[nd[i].len] += nd[i].cnt * nd[i].y;
}
for(int i = 1; i <= n; ++i) {
printf("%lld%c", ans2[i], " \n"[i == n]);
}
}
} pam; char s[MAXN + 5]; int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
while(~scanf("%s", s)) {
int n = strlen(s);
pam.init();
for(int i = 0; s[i] != '\0'; ++i)
pam.extend(s[i]);
//pam.show();
pam.count();
pam.solve();
pam.ans(n);
}
return 0;
}

2019 Multi-University Training Contest 2 - 1009 - 回文自动机的更多相关文章

  1. 2019 Multi-University Training Contest 2 I.I Love Palindrome String(回文自动机+字符串hash)

    Problem Description You are given a string S=s1s2..s|S| containing only lowercase English letters. F ...

  2. 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)

    https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...

  3. [2019杭电多校第二场][hdu6599]I Love Palindrome String(回文自动机&&hash)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6599 题目大意为求字符串S有多少个子串S[l,r]满足回文串的定义,并且S[l,(l+r)/2]也满足 ...

  4. hdu多校第二场1009 (hdu6599) I Love Palindrome String 回文自动机/字符串hash

    题意: 找出这样的回文子串的个数:它本身是一个回文串,它的前一半也是一个回文串 输出格式要求输出l个数字,分别代表长度为1~l的这样的回文串的个数 题解: (回文自动机和回文树是一个东西) 首先用回文 ...

  5. URAL 2040 Palindromes and Super Abilities 2 (回文自动机)

    Palindromes and Super Abilities 2 题目链接: http://acm.hust.edu.cn/vjudge/contest/126823#problem/E Descr ...

  6. URAL 2040 (回文自动机)

    Problem Palindromes and Super Abilities 2 (URAL2040) 题目大意 给一个字符串,从左到右依次添加,询问每添加一个字符,新增加的回文串数量. 解题分析 ...

  7. 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做

    题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...

  8. [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  9. BZOJ2160拉拉队排练——回文自动机

    题目描述 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多 ...

随机推荐

  1. 【NOIP2013模拟联考5】军训

    题目 HYSBZ 开学了!今年HYSBZ 有n 个男生来上学,学号为1-n,每个学生都必须参加军训.在这种比较堕落的学校里,每个男生都会有Gi 个女朋友,而且每个人都会有一个欠扁值Hi.学校为了保证军 ...

  2. Java面试之基础篇(4)

    31.String s = new String("xyz");创建了几个StringObject?是否可以继承String类? 两个或一个都有可能,”xyz”对应一个对象,这个对 ...

  3. 搭建nginx环境(参考腾讯云实验室)

    使用 yum 安装 Nginx: yum install nginx -y 修改 /etc/nginx/conf.d/default.conf,去除对 IPv6 地址的监听,可参考下面的代码示例: s ...

  4. PHP文件操作基本代码

    PHP中提供了一系列的I/O函数,能简捷地实现我们所需要的功能,包括文件系统操作和目录操作(如“复制[copy]”).下面兄弟连PHP培训 小编给大家介绍的是基本的文件读写操作:(1)读文件 ;(2) ...

  5. Java——API文档

    Sun下载JDK--解压缩--javadoc文件(Constuctor Summary[构造方法]+Method Summary[方法])   [Object]   Object类是所有Java类的根 ...

  6. 【bzoj1588】[HNOI2002]营业额统计

    题目描述: 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额. ...

  7. 解决异常信息 Caused by: java.lang.IllegalArgumentException: invalid comparison: java.lang.String and java.util.Date

    原来的xml文件 <if test="null != endDate and '' != endDate"> AND rr.REG_DATE <= #{endDa ...

  8. Initialization of bean failed; nested exception is java.lang.

    网上搜寻各种解说,applicationContext-hibernate.xml 配置错误,jar冲突等等 现场错误图: 解决方法: asm-attrs.jar cglib-nodep-2.1_3. ...

  9. React-Native 之 GD (十七)小时风云榜按钮处理

    小时风云榜按钮处理 在服务器返回给我们的 json 数据中,提供了 hasnexthour 字段,当这个字段返回为 1 的时候,表示后面还有内容,按钮可以点击,否则不能点击,按照这个思路,我们就来完成 ...

  10. C# 防火墙操作之特定端口

    针对将特定端口加入到windows系统的防火墙中,使其允许或禁止通过防火墙.其大概思路是: /// <summary> /// 添加防火墙例外端口 /// </summary> ...