AC自动机已经足够棒了。
但是,好像有时还是要TLE的。
一般的AC自动还是比较好,如果在某些情况下还是会被卡掉,像是这个水题
考试的感觉
我看到这个题后,我清清楚楚的知道,这是个AC自动机+栈。
经过一番努力,把AC自动机打了出来,然后略加修饰,把栈补在里面。
我一复制,一粘贴,更高兴(?)了,过样例了,噫,我要A了。
但是我又随便写了一坨字符进去,然后就,不对了~~~~~~
最后也没调出来,后来我想想,好像是没恢复搜索栈顶元素。
我太菜了。
---以上都是废话---
更改的过程
我T60之后,想了一会,去查了Trie图,但是比较难受。
后来是有大神告诉我,可以用简单的办法构建部分Tire图,优化后就可以AC惹
但是我囿于万恶的板子,一直TLE。
唔啊啊啊啊!
我改了一会,建好图,信心满满,然后又……T了?
后来我又想,又问了几个大佬「没有得到满意的答复」
最后我充满疑惑的看到了我的while,好像不是那么回事
void ffind(){ int j=0; 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!=0){ t-=l->len; p=sta[t-1]; break; } l=l->next; } j++; } }
我为什么要反复去找一个字符呢?
于是删掉while,改成if,AC。
额,一个while卡我6000ms。
分析一下,
我写的板子来自上面的两道题,有重复字符,互为子串的也有
而本题明确说明:N个字符串中无互相包含的
所以这句话就是没有意义的,它反复去找出现这个字符的地方,浪费了众多时间
而我们只需要找上一个字符出现之后的这一个字符就可以
所以,改成if更加正确。
void ffind(){ int j=0; 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!=0){ t-=l->len; p=sta[t-1]; } j++; } }
全代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define N 101010 5 using namespace std; 6 struct ACauto{ 7 ACauto *next,*s[26]; 8 int len; 9 char ch; 10 }s[100*N];int tot=0; 11 ACauto *newACauto(){ 12 tot++; 13 return &s[tot-1]; 14 } 15 ACauto *root=newACauto(); 16 char st[N],ch[N]; 17 ACauto *q[10000000];int f=0,e=0; 18 bool empty(){ 19 if(f==e)return true; 20 return false; 21 } 22 void push(ACauto *x){ 23 e++; 24 q[e]=x; 25 } 26 ACauto* front(){ 27 f++; 28 return q[f]; 29 } 30 void add(const char *c){ 31 int j=0; 32 ACauto *i=root; 33 while(c[j]){ 34 int k=c[j]-'a'; 35 if(i->s[k]==NULL) i->s[k]=newACauto(); 36 i=i->s[k]; 37 i->ch=c[j]; 38 j++; 39 } 40 i->len=j; 41 } 42 void build(){ 43 root->next=NULL; 44 push(root); 45 while(!empty()){ 46 ACauto *n=front(); 47 for(int i=0;i<26;i++){ 48 if(n->s[i]!=NULL){ 49 if(n==root) n->s[i]->next=root; 50 else{ 51 ACauto *p=n->next; 52 while(p!=NULL){ 53 if(p->s[i]!=NULL){ 54 n->s[i]->next=p->s[i]; 55 // n->s[i]=p; 56 break; 57 } 58 p=p->next; 59 } 60 if(p==NULL) n->s[i]->next=root; 61 } 62 push(n->s[i]); 63 } 64 else{ 65 if(n==root) 66 n->s[i]=root; 67 else 68 n->s[i]=n->next->s[i]; 69 } 70 } 71 } 72 } 73 ACauto *sta[N]; 74 int t=0; 75 void pour(){ 76 for(int i=0;i<t;i++){ 77 putchar(sta[i]->ch); 78 } 79 puts(""); 80 } 81 void ffind(){ 82 int j=0; 83 ACauto *p=root; 84 sta[t++]=root; 85 while(st[j]){ 86 int k=st[j]-'a'; 87 while(p!=root && p->s[k]==NULL) p=p->next; 88 p=p->s[k]; 89 sta[t++]=p; 90 if(p==NULL) p=root; 91 ACauto *l=p; 92 if(l->len!=0){ 93 //pour();//cout<<t<<" "<<l->len<<endl; 94 t-=l->len; 95 p=sta[t-1]; 96 } 97 j++; 98 } 99 } 100 int _n=0; 101 void prerun(){ 102 for(int i=0;i<26;i++){ 103 root->s[i]=new ACauto(); 104 root->s[i]->ch='a'+i; 105 } 106 } 107 int main(){ 108 prerun(); 109 scanf("%s",st); 110 scanf("%d",&_n); 111 for(int i=1;i<=_n;i++){ 112 scanf("%s",ch); 113 add(ch); 114 } 115 build(); 116 ffind(); 117 for(int i=1;i<t;i++)putchar(sta[i]->ch); 118 puts(""); 119 return 0; 120 }