题意:给出多种病毒的号码和特征码,计算在某串中各病毒匹配的次数。
解题关键:AC自动机模板题,多组输入坑人。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=96; 5 const int MAXN=50010; 6 int num,ans[1002],nn; 7 char vir[1002][52]; 8 struct Trie{//数组形式 9 int Next[MAXN][N],Fail[MAXN],End[MAXN],root,tot;//大小为所以匹配字符串的总和 10 int newnode(){//结构体内部用 11 for(int i=0;i<N;i++) Next[tot][i]=-1; 12 End[tot++]=0; 13 return tot-1; 14 } 15 void init(){ 16 tot=0; 17 root=newnode(); 18 } 19 void insert(char buf[],int x){ 20 int len=strlen(buf); 21 int now=root;//now是temp指针 22 for(int i=0;i<len;i++){ 23 int k=buf[i]-32; 24 if(Next[now][k]==-1) Next[now][k]=newnode();//next数组代表的是下一个字符索引 25 now=Next[now][k]; 26 } 27 End[now]=x;//end数组是当前字符串的个数.字典中可能有相同的单词,若只算一次,改为1. 28 } 29 void build(){//构造fail指针,后缀是某些前缀 30 queue<int>que; 31 Fail[root]=root; 32 for(int i=0;i<N;i++){ 33 if(Next[root][i]==-1) Next[root][i]=root; 34 else{ 35 Fail[Next[root][i]]=root; 36 que.push(Next[root][i]); 37 } 38 } 39 while(!que.empty()){//bfs,会将所有的匹配子串都遍历到 40 int now=que.front(); 41 que.pop(); 42 for(int i=0;i<N;i++){ 43 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; 44 else{ 45 Fail[Next[now][i]]=Next[Fail[now]][i];//fail指向最长的 46 que.push(Next[now][i]); 47 } 48 } 49 } 50 } 51 void query(char buf[]){ 52 int len=strlen(buf),now=root; 53 for(int i=0;i<len;i++){ 54 now=Next[now][buf[i]-32]; 55 int temp=now; 56 while(temp!=root){ 57 if(End[temp]) ans[End[temp]]++; 58 temp=Fail[temp]; 59 } 60 } 61 } 62 }; 63 64 Trie ac; 65 char buf[2000004]; 66 int n,m; 67 int main(){ 68 while(scanf("%d",&n)!=EOF){ 69 memset(ans,0,sizeof ans); 70 ac.init(); 71 for(int i=1;i<=n;i++){ 72 scanf("%s",vir+i); 73 ac.insert(vir[i],i); 74 } 75 ac.build();//不要忘记build 76 scanf("%s",buf); 77 ac.query(buf); 78 for(int i=1;i<=n;i++){ 79 if(!ans[i]) continue; 80 printf("%s: %d ",vir[i],ans[i]); 81 } 82 } 83 84 return 0; 85 }