AC自动机已经足够棒了。

但是,好像有时还是要TLE的。

一般的AC自动还是比较好,如果在某些情况下还是会被卡掉,像是这个水题


考试的感觉

我看到这个题后,我清清楚楚的知道,这是个AC自动机+栈。

经过一番努力,把AC自动机打了出来,然后略加修饰,把栈补在里面。

我一复制,一粘贴,更高兴(?)了,过样例了,噫,我要A了。

但是我又随便写了一坨字符进去,然后就,不对了~~~~~~

最后也没调出来,后来我想想,好像是没恢复搜索栈顶元素。

我太菜了。

---以上都是废话---


更改的过程

我T60之后,想了一会,去查了Trie图,但是比较难受。

后来是有大神告诉我,可以用简单的办法构建部分Tire图,优化后就可以AC惹

但是我囿于万恶的板子,一直TLE。

唔啊啊啊啊!

我改了一会,建好图,信心满满,然后又……T了?

后来我又想,又问了几个大佬「没有得到满意的答复」

最后我充满疑惑的看到了我的while,好像不是那么回事

void ffind(){
int j=;
ACauto *p=root;
sta[t++]=root;
while(st[j]){
int k=st[j]-'a';
while(p!=root && p->s[k]==NULL) p=p->next;
p=p->s[k];
sta[t++]=p;
if(p==NULL) p=root;
ACauto *l=p;
while(l!=root){//这个while
if(l->len!=){
t-=l->len;
p=sta[t-];
break;
}
l=l->next;
}
j++;
}
}

我为什么要反复去找一个字符呢?

于是删掉while,改成if,AC。

额,一个while卡我6000ms。

分析一下,

我写的板子来自上面的两道题,有重复字符,互为子串的也有

而本题明确说明:N个字符串中无互相包含的

所以这句话就是没有意义的,它反复去找出现这个字符的地方,浪费了众多时间

而我们只需要找上一个字符出现之后的这一个字符就可以

所以,改成if更加正确。

void ffind(){
int j=;
ACauto *p=root;
sta[t++]=root;
while(st[j]){
int k=st[j]-'a';
while(p!=root && p->s[k]==NULL) p=p->next;
p=p->s[k];
sta[t++]=p;
if(p==NULL) p=root;
ACauto *l=p;
if(l->len!=){
t-=l->len;
p=sta[t-];
}
j++;
}
}

全代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#define N 101010
using namespace std;
struct ACauto{
ACauto *next,*s[];
int len;
char ch;
}s[*N];int tot=;
ACauto *newACauto(){
tot++;
return &s[tot-];
}
ACauto *root=newACauto();
char st[N],ch[N];
ACauto *q[];int f=,e=;
bool empty(){
if(f==e)return true;
return false;
}
void push(ACauto *x){
e++;
q[e]=x;
}
ACauto* front(){
f++;
return q[f];
}
void add(const char *c){
int j=;
ACauto *i=root;
while(c[j]){
int k=c[j]-'a';
if(i->s[k]==NULL) i->s[k]=newACauto();
i=i->s[k];
i->ch=c[j];
j++;
}
i->len=j;
}
void build(){
root->next=NULL;
push(root);
while(!empty()){
ACauto *n=front();
for(int i=;i<;i++){
if(n->s[i]!=NULL){
if(n==root) n->s[i]->next=root;
else{
ACauto *p=n->next;
while(p!=NULL){
if(p->s[i]!=NULL){
n->s[i]->next=p->s[i];
// n->s[i]=p;
break;
}
p=p->next;
}
if(p==NULL) n->s[i]->next=root;
}
push(n->s[i]);
}
else{
if(n==root)
n->s[i]=root;
else
n->s[i]=n->next->s[i];
}
}
}
}
ACauto *sta[N];
int t=;
void pour(){
for(int i=;i<t;i++){
putchar(sta[i]->ch);
}
puts("");
}
void ffind(){
int j=;
ACauto *p=root;
sta[t++]=root;
while(st[j]){
int k=st[j]-'a';
while(p!=root && p->s[k]==NULL) p=p->next;
p=p->s[k];
sta[t++]=p;
if(p==NULL) p=root;
ACauto *l=p;
if(l->len!=){
//pour();//cout<<t<<" "<<l->len<<endl;
t-=l->len;
p=sta[t-];
}
j++;
}
}
int _n=;
void prerun(){
for(int i=;i<;i++){
root->s[i]=new ACauto();
root->s[i]->ch='a'+i;
}
}
int main(){
prerun();
scanf("%s",st);
scanf("%d",&_n);
for(int i=;i<=_n;i++){
scanf("%s",ch);
add(ch);
}
build();
ffind();
for(int i=;i<t;i++)putchar(sta[i]->ch);
puts("");
return ;
}

>这里<

T1订正记-AC自动机-从树到图的更多相关文章

  1. hdu 4117 GRE Words (ac自动机 线段树 dp)

    参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...

  2. hdu 4117 -- GRE Words (AC自动机+线段树)

    题目链接 problem Recently George is preparing for the Graduate Record Examinations (GRE for short). Obvi ...

  3. 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)

    [BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...

  4. 【BZOJ2434】【NOI2011】阿狸的打字机(AC自动机,树状数组)

    [BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...

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

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

  6. NOI 2011 阿狸的打字机(AC自动机+主席树)

    题意 https://loj.ac/problem/2444 思路 ​多串匹配,考虑 \(\text{AC}\) 自动机.模拟打字的过程,先建出一棵 \(\text{Trie}\) 树,把它变成自动机 ...

  7. BZOJ2905: 背单词 AC自动机+fail树+线段树

    $zjq$神犇一眼看出$AC$自动机 $Orz$ 直接就讲做法了 首先对每个串建出$AC$自动机 将$fail$树找到 然后求出$dfs$序 我们发现一个单词 $S_i$是$S_j$的子串当且仅当$S ...

  8. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  9. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

随机推荐

  1. ng 表单提交验证

    http://www.runoob.com/try/try.php?filename=try_ng_validate

  2. Java必知必会:异常机制详解

    一.Java异常概述 在Java中,所有的事件都能由类描述,Java中的异常就是由java.lang包下的异常类描述的. 1.Throwable(可抛出):异常类的最终父类,它有两个子类,Error与 ...

  3. 容器vector 迭代器iterator 应用

    #include <iostream> #include <vector> using namespace std; int main() { vector<int> ...

  4. Gulp安装及配合组件构建前端开发一体化(转)

    Gulp安装及配合组件构建前端开发一体化 所有功能前提需要安装nodejs(本人安装版本v0.10.26)和ruby(本人安装版本1.9.3p484). Gulp 是一款基于任务的设计模式的自动化工具 ...

  5. Two

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission( ...

  6. E20180418-hm

    utility n. [计]工具; 公用事业; 功用,效用; 有用的物体或器械; 公用事业公司; identity n. 身份; identifier  n. 识别符; 检验人,标识符; 鉴别器; 编 ...

  7. bzoj 1049: [HAOI2006]数字序列【dp+二分+瞎搞】

    第一问明显就是用b[i]=a[i]-i来做最长不下降子序列 然后第二问,对于一对f[i]=f[j]+1的(i,j),中间的数一定要改的,并且是等于b[i]或者b[j],我不会证,然后因为是随机数据,所 ...

  8. 2019年BAT面试通关宝典:数据结构+JVM+并发编程+分布式...

    前言 金三银四俗称跳槽黄金季,很多同学都想趁着这段时间拿高薪,去更牛逼的公司工作,认识更多大牛,提升自己的职场竞争力. 那怎样才能通过BAT面试官的考核?怎样成为一名Offer收割机? 收割Offer ...

  9. PAT 1035 插入与归并(25)

    原题:https://pintia.cn/problem-sets/994805260223102976/problems/994805286714327040传送门: 根据维基百科的定义: 插入排序 ...

  10. 使用Spring MVC的@RequestBody注解接收Json对象字符串

    最近公司在开发移动APP,APP上通过jQuery提交表单的json字符串格式数据到Java后端,之前通过request手动接收,非常麻烦,其实Spring MVC已经为我们提供了一个注解@Reque ...