【hdu3065-病毒侵袭持续中】AC自动机
题意:给定一些只含大写字母的病毒串,再给一个文本串,问文本串中每个病毒串各出现了多少次。
题解:
就是用AC自动机,在每个节点末尾有个id记录是哪个单词的末尾,然后如果同时是多个单词的末尾就用一个next数组链状记录当前id的下一个值。
多组数据坑死人。坑死人。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<queue> 6 using namespace std; 7 8 const int N=50010,S=2000010,A=26; 9 int n,num,cnt[N],nt[N],fir[N],sum[N]; 10 char ss[N][65],s[S]; 11 queue<int> q; 12 struct node{ 13 int id,fail,son[30]; 14 }a[N]; 15 16 void clear(int x) 17 { 18 a[x].id=a[x].fail=0; 19 memset(a[x].son,0,sizeof(a[x].son)); 20 } 21 22 void trie(char *c,int id) 23 { 24 int x=0,l=strlen(c); 25 for(int i=0;i<l;i++) 26 { 27 int ind=c[i]-'A'+1; 28 if(!a[x].son[ind]) 29 { 30 num++; 31 clear(num); 32 a[x].son[ind]=num; 33 } 34 x=a[x].son[ind]; 35 } 36 if(!a[x].id) a[x].id=id,fir[x]=id; 37 else nt[id]=a[x].id,a[x].id=id; 38 } 39 40 void buildAC() 41 { 42 while(!q.empty()) q.pop(); 43 for(int i=1;i<=A;i++) 44 if(a[0].son[i]) q.push(a[0].son[i]); 45 while(!q.empty()) 46 { 47 int x=q.front();q.pop(); 48 int fail=a[x].fail; 49 for(int i=1;i<=A;i++) 50 { 51 if(a[x].son[i]) 52 { 53 int y=a[x].son[i],z=a[fail].son[i]; 54 a[y].fail=z; 55 if(fir[y]) nt[fir[y]]=a[z].id; 56 else a[y].id=a[z].id; 57 q.push(y); 58 } 59 else a[x].son[i]=a[fail].son[i]; 60 } 61 } 62 } 63 64 void find(char *c) 65 { 66 int x=0,l=strlen(c); 67 for(int i=0;i<l;i++) 68 { 69 if(!(c[i]>='A' && c[i]<='Z')) {x=0;continue;} 70 int ind=c[i]-'A'+1; 71 x=a[x].son[ind]; 72 int p=a[x].id; 73 while(p) 74 { 75 sum[p]++; 76 p=nt[p]; 77 } 78 } 79 } 80 81 int main() 82 { 83 freopen("a.in","r",stdin); 84 freopen("a.out","w",stdout); 85 while(scanf("%d",&n)!=EOF) 86 { 87 num=0; 88 clear(0); 89 memset(nt,0,sizeof(nt)); 90 memset(fir,0,sizeof(fir)); 91 memset(sum,0,sizeof(sum)); 92 scanf("%d",&n); 93 for(int i=1;i<=n;i++) 94 { 95 scanf("%s",ss[i]); 96 trie(ss[i],i); 97 } 98 buildAC(); 99 scanf("%s",s); 100 find(s); 101 for(int i=1;i<=n;i++) 102 if(sum[i]) printf("%s: %d\n",ss[i],sum[i]); 103 } 104 105 return 0; 106 }