其实很久以来我都把sam当成ac自动机了
ac自动机的建立比sam简单多了
直接暴力建字典树,然后暴力跑fail就好了
(挖个坑:去学fail树)
裸题A一道,岂不美哉
1 #include <bits/stdc++.h> 2 #define MAX 1000000 3 using namespace std; 4 int T,n;char ch; 5 struct acm 6 { 7 int cnt,h,t,c[MAX][26],fail[MAX],que[MAX],ret[MAX]; 8 void cl(int now) 9 { 10 for(int i=0;i<26;i++) 11 c[now][i]=0; 12 ret[now]=0; 13 } 14 void clear() 15 { 16 cnt=1; 17 cl(1); 18 } 19 int ins(int now,int pa) 20 { 21 if(c[now][pa]) return c[now][pa]; 22 else 23 { 24 c[now][pa]=++cnt; 25 cl(c[now][pa]); 26 return c[now][pa]; 27 } 28 } 29 void mark(int now) 30 { 31 ++ret[now]; 32 } 33 int go(int now,int pa) 34 { 35 if(c[now][pa]) return c[now][pa]; 36 else return now>1?go(fail[now],pa):1; 37 } 38 void init() 39 { 40 for(fail[1]=que[1]=h=t=1;h<=t;h++) 41 for(int i=0;i<26;i++) 42 if(c[que[h]][i]) 43 { 44 int T; 45 for(T=fail[que[h]];T>1 && !c[T][i];T=fail[T]); 46 if((T==1 && !c[T][i])||(h==1)) fail[c[que[h]][i]]=1; 47 else fail[c[que[h]][i]]=c[T][i]; 48 que[++t]=c[que[h]][i]; 49 } 50 } 51 int count(int now) 52 { 53 if(now==1 || ret[now]==-1) return 0; 54 int rt=count(fail[now])+ret[now]; 55 ret[now]=-1; 56 return rt; 57 } 58 } a; 59 int main() 60 { 61 for(scanf("%d",&T);T;T--) 62 { 63 scanf("%d",&n); 64 a.clear(); 65 for(int i=1;i<=n;i++) 66 { 67 for(ch=getchar();!isalpha(ch);ch=getchar()); 68 int now=1; 69 for(;isalpha(ch);ch=getchar()) 70 now=a.ins(now,ch-‘a‘); 71 a.mark(now); 72 } 73 a.init(); 74 int now=1,ans=0; 75 for(ch=getchar();!isalpha(ch);ch=getchar()); 76 for(;isalpha(ch);ch=getchar()) 77 now=a.go(now,ch-‘a‘), 78 ans+=a.count(now); 79 printf("%d\n",ans); 80 } 81 return 0; 82 }
时间: 2024-11-06 10:53:17