题目意思是,给定一个主串和多个匹配串,问每个匹配串在主串中出现的次数,不为0的输出该匹配串和它出现的次数。
用AC自动机。对每个匹配串赋予其一个标号,当在匹配中成功时,则该下标对应的一个计数数组的值加1。此题多case。。。。。。
#include<cstdio> #include<cstring> #include<iostream> #include<utility> #include<string> #include<set> #include<vector> #include<stack> #include<algorithm> #include<queue> #include<cstdlib> #include<cmath> using namespace std; const int M=3000000; const int N=2000; const int MN=1000; const int kind=30; char str[N][MN]; char web[M]; struct Node { int num; Node *next[kind],*fail; void init() { num=0; fail=NULL; memset(next,NULL,sizeof(next)); }; }*root,pp[M],*que[10*M]; int nc; int cnt[M/3]; int n; void init() { nc=0; pp[nc].init(); root=&pp[nc++]; memset(cnt,0,sizeof(cnt)); } void insert(char s[],int num) { Node *p=root; for(int i=0;s[i];i++) { if(p->next[s[i]-'A']==NULL) { pp[nc].init(); p->next[s[i]-'A']=&pp[nc++]; } p=p->next[s[i]-'A']; } p->num=num; } void ac_auto() { int front=0,rear=0; Node *cur,*ptr; que[rear++]=root; root->fail=NULL; while(front<rear) { cur=que[front++]; for(int i=0;i<27;i++) { if(cur->next[i]==NULL) continue; if(cur==root) { cur->next[i]->fail=root; que[rear++]=cur->next[i]; continue; } else { for(ptr=cur->fail;ptr!=NULL;ptr=ptr->fail) { if(ptr->next[i]!=NULL) { cur->next[i]->fail=ptr->next[i]; break; } } if(ptr==NULL) { cur->next[i]->fail=root; } que[rear++]=cur->next[i]; } } } } void query() { Node *r=root,*p,*temp; int i=0; while(web[i]) { int index=web[i]-'A'; if(index>25 || index<0) { r=root; i++; continue; } while(r->next[index]==NULL && r!=root) { r=r->fail; } r=r->next[index]; if(r==NULL) r=root; temp=r; while(temp!=root) { cnt[temp->num]++; temp=temp->fail; } i++; } } int main() { while(scanf("%d",&n)==1) { getchar(); init(); for(int i=1;i<=n;i++) { scanf("%s",str[i]); insert(str[i],i); } ac_auto(); scanf("%s",web);; query(); for(int i=1;i<=n;i++) if(cnt[i]>0) { printf("%s: %d\n",str[i],cnt[i]); } } return 0; }