bzoj2434阿狸的自动机
转载自 http://www.cnblogs.com/zj75211/p/6934976.html
●BZOJ 2434: [Noi2011]阿狸的打字机
●赘述题目
(题意就不赘述了)
●解法:
●我先想的一个比较暴力的方法(要TLE):
(ac自动机)先求出last数组(参见刘汝佳的解释:last[j]:表示j节点沿着失配指针往回走时,遇到的下一个单词节点(即单词在此结束)的编号),然后对输入的编号为y的字符串的每一个位置进行递归寻找是否能连上x字符串的结束节点。(给出失败代码片段图,就不解释了)
●正解:
(ac自动机)求出fail数组,然后以fail数组建树,如图
(看啊,红色的边和各点形成了另一棵树)
那么(看红树),若一个点在某个字符串结束节点的子树内,那么该字符串则出现在那个点所在的字符串里;如图中的a-b-c字符串和c字符串。
现在,我们若要求x字符串在y内出现了几次,就只需求以x的结束节点为根的子树内,有多少个节点是y字符串上的。
如何做呢?
将询问离线,y相同询问的弄在一起;
然后求出红树的dfs序(有点诡异,看代码);
我们再遍历一遍输入的字符串:
对于输入的‘a’-‘z’,把对应的dfs序中其出现的位置的值加1,用树状数组维护;
对于输入的‘B’,现在的字符所对应的dfs序中的位置的值减1;
对于遇到的c个‘P’,我们不难发现,现在的树状树状维护的便是第c个字符串的每一个字符在dfs序中的位置的值所加1后的结果。接着便可用区间查询求出y==c的询问的答案。
那么上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #include<iostream> using namespace std; struct node{ int x,y; } q[100005]; struct edge{ int to,next; }e[200005]; int ch[100005][27]; int val[100005],fail[100005],fa[100005],fini[100005],l[100005],r[100005],ans[100005]; int head[100005],headq[100005],nxt[100005],lat[100005],c[150000]; char x[100005]; int cnt,pnt,ent=1,dnt,lx; int idx( char x) { return x- 'a' ;} void modify( int u, int d) { for ( int i=u;i<=dnt;i+=i&(-i)) c[i]+=d;} int query( int u) { int sum=0; for ( int i=u;i;i-=i&(-i)) sum+=c[i]; return sum;} void add( int u, int v) { e[ent]=(edge){v,head[u]};head[u]=ent++; e[ent]=(edge){u,head[v]};head[v]=ent++; } void read_trie() { int u=0; for ( int i=1;i<=lx;i++) { if (x[i]== 'B' ) u=fa[u]; else if (x[i]== 'P' ) val[u]=++pnt,fini[pnt]=u; else { int c=idx(x[i]); if (!ch[u][c]) ch[u][c]=++cnt,fa[ch[u][c]]=u; u=ch[u][c]; } } } void get_fail() { queue< int > q; for ( int c=0;c<26;c++) { int u=ch[0][c]; if (u) q.push(u);} while (!q.empty()) { int r=q.front(); q.pop(); for ( int c=0;c<26;c++) { if (!ch[r][c]) continue ; int u=ch[r][c]; q.push(u); int v=fail[r]; while (v&&!ch[v][c]) v=fail[v]; fail[u]=ch[v][c]; } } } //---------------------------------------------------------------------- void dfs_xu( int u, int fa) { l[u]=++dnt; for ( int i=head[u];i;i=e[i].next) if (e[i].to!=fa) dfs_xu(e[i].to,u); r[u]=dnt; } void work() { int m; scanf ( "%d" ,&m); for ( int i=1;i<=m;i++) { scanf ( "%d%d" ,&q[i].x,&q[i].y); nxt[i]=lat[q[i].y]; lat[q[i].y]=i; } for ( int i=1;i<=cnt;i++) add(i,fail[i]); dfs_xu(0,0); int p=0,id=0; for ( int i=1;i<=lx;i++) { if (x[i]== 'P' ) { id++; for ( int j=lat[id];j;j=nxt[j]) { int u=fini[q[j].x]; ans[j]=query(r[u])-query(l[u]-1); } } else if (x[i]== 'B' ) modify(l[p],-1),p=fa[p]; else p=ch[p][idx(x[i])],modify(l[p],1); } for ( int i=1;i<=m;i++) printf ( "%d\n" ,ans[i]); } int main() { scanf ( "%s" ,x+1); lx= strlen (x+1); read_trie(); get_fail(); work(); return 0; } |
bzoj2434阿狸的自动机的更多相关文章
- [NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]
题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 ...
- bzoj2434 阿狸的打字机
题目链接 思路 可以发现,其实题目中所描述的操作,就是在\(AC\)自动机上走的过程.输出就是打上标记.删除就是返回父亲节点. 然后看询问.每次询问字符串\(x\)在字符串中\(y\)出现的次数.其实 ...
- 【字符串】BZOJ上面几个AC自动机求最为字串出现次数的题目
(一下只供自己复习用,目的是对比这几个题,所以写得不详细.需要细节的可以参考其他博主) [BZOJ3172:单词] 题目: 某人读论文,一篇论文是由许多(N)单词组成.但他发现一个单词会在论文中出现很 ...
- AC自动机题单
AC自动机题目 真的超级感谢xzy 真的帮到我很多 题单 [X] [luogu3808][模板]AC自动机(简单版) https://www.luogu.org/problemnew/show/P38 ...
- fail树
前置技能:AC自动机 假设我们有了一个AC自动机,然后在上面进行字符串匹配. 上面是一个有四个字符串的AC自动机(abcde.aacdf.cdf.cde),虚线是fail指针,实线是转移. 这是上一次 ...
- 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- 【BZOJ2434】【NOI2011】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- 【bzoj2434】: [Noi2011]阿狸的打字机 字符串-AC自动机-BIT
[bzoj2434]: [Noi2011]阿狸的打字机 x串在y串上的匹配次数就是y在自动机所有节点上能够通过fail走到x最后一个节点的个数 (就是y串任意一个前缀的后缀能匹配到x的个数)和[bzo ...
随机推荐
- Lucene 的索引文件锁原理
Lucene 的索引文件锁原理 2016/11/24 · IT技术 · lucene 环境 Lucene 6.0.0Java “1.8.0_111”OS Windows 7 Ultimate 线程 ...
- Flask 学习 十二 用户评论
评论在数据库中的表示 由于评论和2个模型有关系,分别是谁发了评论,以及评论了哪个文章,所以这次要更新数据库模型 models.py 创建用户评论数据库模型 class Comment(db.Model ...
- NOIP2012 提高组 Day 2
http://www.cogs.pro/cogs/page/page.php?aid=16 期望得分:100+100+0=0 实际得分:100+20+0=120 T2线段树标记下传出错 T1 同余方程 ...
- 微信支付get_brand_wcpay_request:fail
最近做了微信支付功能,和后端一起踩坑中,微信一直报错:get_brand_wcpay_request:fail 出现该问题的原因: 1.生成的sign签名有问题 2.支付授权目录配置有问题 在经过仔细 ...
- JAVA_SE基础——55.自定义异常类
在Java中已经提供了大量的异常类,但是这些异常类有时野很难满足开发者的要求,所以用户可以根据自己的需要来定义自己的异常类.但自定义的异常类必须继承自Exception或其子类. 可以自定义出的问题称 ...
- Python——cmd调用(os.system阻塞处理)
os.system(返回值为0,1,2) 0:成功 1:失败 2:错误 os.system默认阻塞当前程序执行,在cmd命令前加入start可不阻塞当前程序执行. 例如: import os os.s ...
- wordpress | WP Mail SMTP使用QQ邮箱发布失败的解决办法
在使用contact form 7插件时遇到邮件发送失败的问题,经过检查发现是因为服务器不支持mail()函数,判断是否支持mail()函数可以参考http://www.diyzhan.com/201 ...
- 新概念英语(1-135)The latest report
Lesson 135 The latest report 最新消息 Listen to the tape then answer this question. Is Karen Marsh going ...
- 开发技巧(3-1)Eclipse查找关键字
1.选择资源目录->选择search-file菜单 2.在弹出的对话框中, 输入要[搜索的字符串],选择[selected resources],点击[search]按钮 3.搜索结果
- io使用的设计模式
File f = new File("c:/a.txt"); 1. FileInputStream fis = new FileInputStream(f); 2. Reader ...