最近几天一直在做有关后缀自动机的题目
感觉似乎对后缀自动机越来越了解了呢!喵~
这题还是让我受益颇多的,首先搞一个后缀自动机是妥妥的了
可是搞完之后呢?
我们来观察 step 这个变量,每个节点的 step 是从根节点到此节点所经过的最长步数
那么也就是以该点为结尾的最长的后缀长度
如何统计不被 Bi 串包含的子串呢?
其实很简单,维护每个节点所能匹配的最长的字符串长度
然后 节点->step-max(该节点所能匹配的最长的字符串长度, 节点->fail->step) 就是答案了
因为 S[0..节点->step-1] 必是原串的一个后缀,而 节点所能匹配的最长字符串长度 d 说明 S[节点->step-d..节点->step-1] 是出现在了某个 Bi 串中的
只不过把每个串在自动机上跑一遍并不能得到每个节点所能匹配的最长长度
因为当该节点被匹配时,该结点的 fail 指针所指向的节点也必然被匹配到了
我们需要一个拓扑排序,按拓扑序来更新答案,并同时更新每个节点的 fail 指针指向的点的匹配长度
教练,我不想写拓扑排序~
我才不会说按 step 从大到小的顺序就是拓扑序呢喵~
namespace 写写被 hdu 怒骂 TLE TAT ,这是多么痛的领悟……
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define ord(ch) ((ch)-'a') 5 typedef long long llint; 6 const int sizeOfString=550005; 7 const int sizeOfMemory=550005<<1; 8 const int sizeOfType=26; 9 10 inline int max(int x, int y) {return x>y?x:y;} 11 12 struct node 13 { 14 int step; 15 int same; 16 node * fail; 17 node * ch[sizeOfType]; 18 }; 19 node memory[sizeOfMemory]; int port; 20 node * dfa=memory, * last; 21 inline node * newnode(node * t=NULL) 22 { 23 node * newt=memory+(port++); 24 newt->step=0; 25 newt->same=0; 26 if (t) newt->fail=t->fail, t->fail=newt, memcpy(newt->ch, t->ch, sizeof t->ch); 27 else newt->fail=NULL, memset(newt->ch, 0, sizeof newt->ch); 28 return newt; 29 } 30 inline void insert(int w) 31 { 32 node * p=last, * newp=newnode(); 33 newp->step=p->step+1; 34 35 for ( ;p->ch[w]==NULL;p=p->fail) p->ch[w]=newp; 36 if (p->ch[w]==newp) 37 newp->fail=dfa; 38 else 39 { 40 node * q=p->ch[w]; 41 if (q->step==p->step+1) 42 newp->fail=q; 43 else 44 { 45 node * newq=newnode(q); 46 newq->step=p->step+1; 47 newp->fail=newq; 48 for ( ;p->ch[w]==q;p=p->fail) p->ch[w]=newq; 49 } 50 } 51 52 last=newp; 53 } 54 inline void search(char * s) 55 { 56 int len=strlen(s); 57 int tot=0; 58 node * t=dfa; 59 for (int i=0;i<len;i++) 60 { 61 int w=ord(s[i]); 62 if (t->ch[w]) 63 { 64 t=t->ch[w]; 65 t->same=max(t->same, ++tot); 66 } 67 else 68 { 69 node * j; 70 for (j=t->fail;j!=dfa && !j->ch[w];j=j->fail); 71 if (j->ch[w]) 72 { 73 t=j->ch[w]; 74 t->same=max(t->same, tot=(j->step+1)); 75 } 76 else 77 { 78 t=dfa; 79 tot=0; 80 } 81 } 82 } 83 } 84 inline llint calc(int len) 85 { 86 static node * p[sizeOfMemory]; 87 static int cnt[sizeOfString]; 88 llint ret=0; 89 90 memset(cnt, 0, sizeof(cnt)); 91 for (int i=0;i<port;i++) cnt[dfa[i].step]++; 92 for (int i=1;i<=len;i++) cnt[i]+=cnt[i-1]; 93 for (int i=0;i<port;i++) p[--cnt[dfa[i].step]]=&dfa[i]; 94 for (int i=port-1;i>0;i--) 95 { 96 p[i]->fail->same=max(p[i]->fail->same, p[i]->same); 97 if (p[i]->same<p[i]->step) 98 ret+=p[i]->step-max(p[i]->same, p[i]->fail->step); 99 } 100 101 return ret; 102 } 103 104 int T, n; 105 char str[sizeOfString], s[sizeOfString]; 106 107 int main() 108 { 109 int cases=0; 110 111 for (scanf("%d", &T);T;T--) 112 { 113 scanf("%d", &n); 114 scanf("%s", str); 115 port=0; dfa=newnode(); dfa->fail=dfa; last=dfa; 116 int len=strlen(str); 117 for (int i=0;i<len;i++) 118 insert(ord(str[i])); 119 for (int i=1;i<=n;i++) 120 { 121 scanf("%s", s); 122 search(s); 123 } 124 printf("Case %d: %I64d ", ++cases, calc(len)); 125 } 126 127 return 0; 128 }