2019 Multi-University Training Contest 2 - 1009 - 回文自动机
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 - 回文自动机的更多相关文章
- 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 ...
- 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)
https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...
- [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]也满足 ...
- hdu多校第二场1009 (hdu6599) I Love Palindrome String 回文自动机/字符串hash
题意: 找出这样的回文子串的个数:它本身是一个回文串,它的前一半也是一个回文串 输出格式要求输出l个数字,分别代表长度为1~l的这样的回文串的个数 题解: (回文自动机和回文树是一个东西) 首先用回文 ...
- URAL 2040 Palindromes and Super Abilities 2 (回文自动机)
Palindromes and Super Abilities 2 题目链接: http://acm.hust.edu.cn/vjudge/contest/126823#problem/E Descr ...
- URAL 2040 (回文自动机)
Problem Palindromes and Super Abilities 2 (URAL2040) 题目大意 给一个字符串,从左到右依次添加,询问每添加一个字符,新增加的回文串数量. 解题分析 ...
- 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做
题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...
- [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串
回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...
- BZOJ2160拉拉队排练——回文自动机
题目描述 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多 ...
随机推荐
- 原创——Nginx基础
Nginx基础 一.Nginx概述: Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx ...
- 小程序-登录-token
1.前端调用wx.login()获取code值 2.前端通过调用wx.getUserInfo获取iv.rawData.signature.encryptedData等加密数据,传递给后端 3.服务器通 ...
- JSP上传整个文件夹
文件上传是最古老的互联网操作之一,20多年来几乎没有怎么变化,还是操作麻烦.缺乏交互.用户体验差. 一.前端代码 英国程序员Remy Sharp总结了这些新的接口 ,本文在他的基础之上,讨论在前端采用 ...
- ASCII,Unicode,UTF-8
ASCII ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英 ...
- 3D Computer Grapihcs Using OpenGL - 07 Passing Data from Vertex to Fragment Shader
上节的最后我们实现了两个绿色的三角形,而绿色是直接在Fragment Shader中指定的. 这节我们将为这两个三角形进行更加自由的着色——五个顶点各自使用不同的颜色. 要实现这个目的,我们分两步进行 ...
- permutation 2
permutation 2 猜了发结论过了== $N$个数的全排列,$p_{1}=x,p_{2}=y$要求$|p_{i+1}-p_{i}|<=2|$求满足条件的排列个数. 首先考虑$x=1,y= ...
- Oracle Fetch子句
Oracle Fetch子句 作者:初生不惑 Oracle基础 评论:0 条 Oracle技术QQ群:175248146 在本教程中,将学习如何使用Oracle FETCH子句来限制查询返回的行数. ...
- 使用JLDAP操作LDAP,包含匿名连接、ldif导入导出、获取根节点、对数据的操作、LDAP错误码解析等
bean类 package com.cn.ccc.ggg.ldap.model; import javax.persistence.Entity; import javax.persistence.T ...
- Elasticsearch的聚合操作
ES的聚合: Metrics 简单的对过滤出来的数据集进行avg,max等操作,是一个单一的数值. bucket 可以理解为将过滤出来的数据集按条件分成多个小数据集,然后Metrics会分别作用在这些 ...
- 在 mac 系统上安装 python 的 MySQLdb 模块
在 mac 系统上安装 python 的 MySQLdb 模块 特别说明:本文主要参考了Mac系统怎么安装MySQLdb(MySQL-Python) 第 1 步:下载 MySQL-python-1.2 ...