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树+优化的更多相关文章

  1. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Sta ...

  2. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  3. BZOJ 2434: [Noi2011]阿狸的打字机 AC自动机+fail树+线段树

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  4. [NOI2011][bzoj2434] 阿狸的打字机 [AC自动机+dfs序+fail树+树状数组]

    题面 传送门 正文 最暴力的 最暴力的方法:把所有询问代表的字符串跑一遍kmp然后输出 稍微优化一下:把所有询问保存起来,把模板串相同的合并,求出next然后匹配 但是这两种方法本质没有区别,都是暴力 ...

  5. BZOJ2434:[NOI2011]阿狸的打字机(AC自动机,线段树)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  6. BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...

  7. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  8. BZOJ2434 [Noi2011]阿狸的打字机 【AC自动机 + fail树 + 树状数组】

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 3610  Solved: 1960 [Submit][S ...

  9. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

随机推荐

  1. 十一、从头到尾彻底解析Hash 表算法

    在研究MonetDB时深入的学习了hash算法,看了作者的文章很有感触,所以转发,希望能够使更多人受益! 十一.从头到尾彻底解析Hash 表算法 作者:July.wuliming.pkuoliver  ...

  2. [笔记]一个测试浏览器对html5支持的网站

    用需要测试的浏览器打开这个地址:http://html5test.com/

  3. Ubuntu14.04安装配置ndnSIM

    Ubuntu14.04安装配置ndnSIM 预环境 Ubuntu14.04官方系统 请先使用sudo apt-get update更新一下源列表 安装步骤 安装boost-lib sudo apt-g ...

  4. JAVA类与对象(七)------继承

    理解:继承可以理解为一个对象获取属性的过程.如果类A是类B的父类,而类B是类C的父类,我们也称C是A的子类,类C是从类A继承而来.    在java中,类的继承是单一继承,也就是说,一个子类只能拥有一 ...

  5. unity工具IGamesTools之批量生成帧动画

    unity工具IGamesTools批量生成帧动画,可批量的将指定文件夹下的帧动画图片自动生成对应的资源文件(Animation,AnimationController,Prefabs) unity工 ...

  6. [shell基础]——uniq命令

    uniq命令常见选项      去除重复行      -u  显示不重复的行      -d  显示有重复的行      -c  打印每一行重复的次数 测试文本内容如下: # cat 4.txt 11 ...

  7. 微软职位内部推荐-Senior Software Engineer

    微软近期Open的职位: Are you looking for a big challenge? Do you know why Big Data is the next frontier for ...

  8. java笔试题(1)

    char型变量中能不能存贮一个中文汉字? char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦.不过,如果某个特殊的汉字没 ...

  9. 查看Android应用签名信息

    本文档介绍在Android下如何查看自己的应用签名及三方APK或系统APK签名信息,包含其中的MD5.SHA1.SHA256值和签名算法等信息. 1.查看自己的应用签名 可以通过两种方式查看 (1)  ...

  10. Incorrect string value: '\xF0\xA1\xA1\x92' for column 'herst' at row 1

    Incorrect string value: '\xF0\xA1\xA1\x92' for column 'herst' at row 1[转] 1.一般来说MySQL(小于5.5.3)字符集设置为 ...