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. 基于http方式搭建YUM源服务器

    基于http方式搭建YUM源服务器 (2012-09-21 11:59:14) 转载▼ 标签: yum linux lnmp lamp http 分类: Linux 为了方便公司80多台Linux服务 ...

  2. CSS3——制作图片翻页的小动画

    觉得还挺有意思的嘻嘻~ 这里有一个问题要注意一下,图片反转过程中可能会遇到一种如下所示的跳变bug: 这玩意一出来吓我一大跳,显然这种用户体验是很不好的,解决方法: 在.pic, .info{...} ...

  3. 封装插件并发布到npm的历程

    1.封装插件 2.使用webpack打包的时候发生了很多问题 3.过程很反复 4.但最终还是发布成功了

  4. Java中日期

    package com.shiro.springbootshiro; import java.text.SimpleDateFormat; import java.util.Date; /** * 作 ...

  5. Android环境配置之正式版AndroidStudio1.0

    昨天看见 Android Studio 1.0 正式版本发布了:心里挺高兴的. 算是忠实用户了吧,从去年开发者大会一开始出现 AS 后就开始使用了:也是从那时开始就基本没有用过 Eclipse 了:一 ...

  6. div中图片居中

    直接上图

  7. 使用struts2的内置标签,采用submit()提交表单时,浏览器报404

    如图 url是没有问题的,结果我将提交方式改为get时,发现有2个参数的name值是一样的,如下图, 解决方法:将name的值修改就OK了.

  8. 【转】vux (scroller)上拉刷新、下拉加载更多

    1)比较关键的地方是要在 scroller 组件上里加一个 ref 属性 <scroller :lockX="true" height="-170" :p ...

  9. SpringMVC常用方法总结

    *) @RequestMapping(value="/xxx/{id}",method={RequestMethod.GET}) method 不写的话,默认GET.POST都支持 ...

  10. dropna()函数

    参数: axis:       default 0指行,1为列 how:       {‘any’, ‘all’}, default ‘any’指带缺失值的所有行;'all’指清除全是缺失值的 thr ...