【bzoj2434-阿狸的打字机】AC自动机+fail树+优化
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23083
Description
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。
经阿狸研究发现,这个打字机是这样工作的:
l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。
l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
Sample Input
aPaPBbP
3
1 2
1 3
2 3
Sample Output
2
1
0
题解:这道题做了好久。。哭泣。。。。。。。
主要是超时的问题。
fail树:按照AC自动机上fail的反向边建立的树。
如样例:
可以知道:failtree上,任意一点所代表的子串(即以trie上根到该点的串)是它在fail树上的子树任意一点的子串。
就是说,x是y的祖先,那么以y为结尾的串一直fail可以fail到x,就是x是y的子串。
那么现在可以得出一个简单粗暴的方法:
对于每个询问(x,y),求x在y上出现的次数,我们就可以在fail树上找到x串末尾的点A,然后询问y串在fail树上的每一个点是否是x的子树中的点,是就ans++。
但是明显,这个方法慢出天际了。。。。
优化:
(三颗星)离线。在fail树上用dfn给节点编号,则每一个点的子树在节点号上是连续的一段。在trie上走一遍,每到一个点x就在树状数组的dfn[x]位置+1,每离开一个点就在树状数组的dfn[x]位置-1。然后每当走到一个串的末尾,就询问每个对应要询问的x串,给fail树上它的子树求和,就是树状数组上getsum A~next[A]-1,这样就求出了y上多少个点为末尾可以fail到x,就是该询问(x,y)的答案。
后面就是我的错误点了:
(1)循环字符串的时候不要打for(int i=0;i<strlen(s);i++) ... 拿个变量存一下strlen(s)。。。超慢的。。
(2)做trietree的时候不用每次从头开始。。接着上一次的末尾就可以了。。快超多。。
(3)最后询问的时候不要把所有询问扫一遍。。用个first存y的边目录啊。。
血与泪啊。。
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
using namespace std; const int N=,S=;
struct node{
int k,fa,fail,son[];
}a[N];
struct edge{
int x,y,next,fa,ans;
}b[N],t[N];
char s[N];
int pre,m,tl,sl,num,cnt_s,len,cnt_dfn;
int last[N],c[N],sk[N],dfn[N],next[N],first[N],fir[N];
queue<int> q; void clear(int x)
{
a[x].fa=a[x].k=a[x].fail=;
memset(a[x].son,,sizeof(a[x].son));
} void buildAC()
{
while(!q.empty()) q.pop();
for(int i=;i<=S;i++)
if(a[].son[i]) q.push(a[].son[i]);
while(!q.empty())
{
int x=q.front();q.pop();
int fail=a[x].fail;
for(int i=;i<=S;i++)
{
if(a[x].son[i])
{
a[a[x].son[i]].fail=a[fail].son[i];
q.push(a[x].son[i]);
}
else a[x].son[i]=a[fail].son[i];
}
}
} void ins(int x,int y,bool bk)
{
if(!bk)
{
b[++len].x=x;b[len].y=y;
b[len].next=first[x];first[x]=len;
}
else
{
t[++tl].x=x;t[tl].y=y;t[tl].ans=;
t[tl].next=fir[x];fir[x]=tl;
}
} void dfs(int x)
{
dfn[x]=++cnt_dfn;
for(int i=first[x];i;i=b[i].next)
{
int y=b[i].y;
dfs(y);
}
next[x]=cnt_dfn;
} void build_fail_tree()
{
for(int i=;i<=num;i++) ins(a[i].fail,i,);
dfs();
} int lowbit(int x){return x&(-x);}
void add(int x,int d){for(int i=x;i<=N-;i+=lowbit(i)) c[i]+=d;}
int getsum(int x)
{
int ans=;
for(int i=x;i>=;i-=lowbit(i)) ans+=c[i];
return ans;
} int main()
{
freopen("a.in","r",stdin);
freopen("me.out","w",stdout);
num=;cnt_s=;cnt_dfn=;len=;pre=;tl=;clear();
memset(fir,,sizeof(fir));
memset(first,,sizeof(first));
memset(c,,sizeof(c));
scanf("%s",s);
//build trie tree
int strl=strlen(s),now=;
for(int i=;i<strl;i++)
{
if(s[i]=='P')
{
a[now].k=;
last[++cnt_s]=now;
}
else if(s[i]=='B') now=a[now].fa;
else
{
int ind=s[i]-'a'+;
if(!a[now].son[ind])
{
num++;clear(num);
a[now].son[ind]=num;
a[num].fa=now;
}
now=a[now].son[ind];
}
}
//build ac
buildAC();
//build fail tree
build_fail_tree();
scanf("%d",&m);
for(int i=;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(y,x,);
}
//find
now=,cnt_s=;
for(int i=;i<strl;i++)
{
if(s[i]=='B')
{
add(dfn[now],-);
now=a[now].fa;
}
else if(s[i]=='P')
{
cnt_s++;
for(int j=fir[cnt_s];j;j=t[j].next)
{
int st=dfn[last[t[j].y]],ed=next[last[t[j].y]];
t[j].ans=getsum(ed)-getsum(st-);
}
}
else
{
int ind=s[i]-'a'+;
now=a[now].son[ind];
add(dfn[now],);
}
}
for(int i=;i<=m;i++)
printf("%d\n",t[i].ans);
return ;
}
【bzoj2434-阿狸的打字机】AC自动机+fail树+优化的更多相关文章
- 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2022 Solved: 1158[Submit][Sta ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- [NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]
题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 ...
- BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
- BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 3610 Solved: 1960 [Submit][S ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
随机推荐
- linux eclipse
方法一: 此外,众所周知,Eclipse是Java程序,因此很容易就实现了跨平台,也是众所周知,Java的大型程序非常吃内存,即使有512MB内存, 仍然感觉Eclipse的启动速度很慢.个人认为1G ...
- 如何在Window上使用Git
开始的时候同事只给了一个地址,类似这样:git@111.111.1.1:ABCDEF (1)如何在Windows上使用Git 有一篇博客不错:http://www.tuicool.com/articl ...
- [转]ASP.NET MVC Spring.NET NHibernate 整合
请注明转载地址:http://www.cnblogs.com/arhat 在整合这三个技术之前,首先得说明一下整合的步骤,俗话说汗要一口一口吃,事要一件一件做.同理这个三个技术也是.那么在整合之前,需 ...
- [quote ]ffmpeg, gstreamer, Raspberry Pi, Windows Desktop streaming
[quote ]ffmpeg, gstreamer, Raspberry Pi, Windows Desktop streaming http://blog.pi3g.com/2013/08/ffmp ...
- Qt---在QLabel上实现系统时间
参考:http://blog.csdn.net/g457499940/article/details/11923887 ---------------------------------------- ...
- JavaScript设计模式与开发实践——JavaScript的多态
“多态”一词源于希腊文polymorphism,拆开来看是poly(复数)+ morph(形态)+ ism,从字面上我们可以理解为复数形态. 多态的实际含义是:同一操作作用于不同的对象上面,可以产生不 ...
- 搭建SpringMVC+MyBatis开发框架三
新增spingmvc.xml配置 在WEB-INF下新增spingmvc.xml,主要是配置spring扫描的包:  <?xml version="1.0" encodin ...
- 读《我是一只IT小小鸟》有感
时间太瘦,指缝太宽.一晃一学期过去了,有些迷茫,但也相信未来是美好的.当我看完<我是一只IT小小鸟>这本书之后,心中更是感慨万千.每一个励志的故事都值得欣赏.深思,甚至我还幻想 ...
- httpclient模拟浏览器get\post
一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等.所访问的这些页面有的仅 仅是一些普通的页面,有的需要用户登录后方可使用,或者需 ...
- Redis 起步
Rdis和JQuery一样是纯粹为应用而产生的,这里记录的是在CentOS 5.7上学习入门文章: 1.Redis简介 Redis是一个key-value存储系统.和Memcached类似,但是解决 ...