/*
2896很裸的AC自動機,注意判重就ok了 */ #include<cstdio> #include<cstring> #include <iostream> #include<algorithm> #include<queue> #include<set> using namespace std; const int kind = 128;set<int> S;set<int>::iterator it; struct node{ node *fail; //失敗指標 node *next[kind]; //Tire每個節點的26個子節點(最多26個字母) int count,id; //是否為該單詞的最後一個節點 node(){ //建構函式初始化 fail=NULL; count=0; memset(next,NULL,sizeof(next)); } }; //隊列,方便用於bfs構造失敗指標 char keyword[201]; //輸入的單詞 char str[10009]; //模式串 int head,tail; //隊列的頭尾指標 void insert(char *str,node *root,int id){ node *p=root; int i=0,index; while(str[i]){ index=str[i]; if(p->next[index]==NULL) p->next[index]=new node(); p=p->next[index]; i++; } p->count++; p->id=id; } void build_ac_automation(node *root){ int i; root->fail=NULL; queue<node *> q; q.push(root); while(!q.empty()){ node *temp=q.front();q.pop(); node *p=NULL; for(i=0;i<128;i++){ if(temp->next[i]!=NULL){ if(temp==root) temp->next[i]->fail=root; else{ p=temp->fail; while(p!=NULL){ if(p->next[i]!=NULL){ temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL) temp->next[i]->fail=root; }q.push(temp->next[i]); } } } }int n,m; int query(node *root){ int i=0,cnt=0,index,len=strlen(str); node *p=root; while(str[i]){ index=str[i]; while(p->next[index]==NULL && p!=root) p=p->fail; p=p->next[index]; p=(p==NULL)?root:p; node *temp=p; while(temp!=root){ cnt+=temp->count; if(temp->id>0&&temp->id<=n) S.insert(temp->id); temp=temp->fail; } i++; } return cnt; } int main(){ char c; while(scanf("%d",&n)!=EOF) { node *root=new node(); for(int i=1;i<=n;i++) { scanf("%s",keyword); insert(keyword,root,i); } build_ac_automation(root);scanf("%d",&m);int tot=0;for(int i=1;i<=m;i++){ S.clear(); scanf("%s",str); query(root); if(S.size()>0) { printf("web %d:",i); for(it=S.begin();it!=S.end();it++) printf(" %d",*it); puts(""); tot++; }}printf("total: %d\n",tot); } return 0; } /* 給定匹配串和母串,統計有多少個這樣的匹配串,它自身是母串的子串或者 它翻轉後是母串的子串; 剛開始在建字典樹的時候把所以匹配串和它的子串都插入,杯具的mle 後來只插入自身,匹配的時候讓母串分別順序和逆序匹配一遍就ok了 很有啟發意義。。。 */ #include<cstdio> #include<cstring> #include <iostream> #include<algorithm> #include<queue> using namespace std; const int kind = 26; struct node{ node *fail; //失敗指標 node *next[kind]; //Tire每個節點的26個子節點(最多26個字母) int count; //是否為該單詞的最後一個節點 node(){ //建構函式初始化 fail=NULL; count=0; memset(next,NULL,sizeof(next)); } }; //隊列,方便用於bfs構造失敗指標 char keyword[1001]; //輸入的單詞 char str[5100001]; //模式串 int head,tail; //隊列的頭尾指標 void insert(char *str,node *root){ node *p=root; int i=0,index; while(str[i]){ index=str[i]-'A'; if(p->next[index]==NULL) p->next[index]=new node(); p=p->next[index]; i++; } p->count++; } void build_ac_automation(node *root){ int i; root->fail=NULL; //q[head++]=root; queue<node *> q; q.push(root); while(!q.empty()){ node *temp=q.front();q.pop(); node *p=NULL; for(i=0;i<26;i++){ if(temp->next[i]!=NULL){ if(temp==root) temp->next[i]->fail=root; else{ p=temp->fail; while(p!=NULL){ if(p->next[i]!=NULL){ temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL) temp->next[i]->fail=root; } // q[head++]= q.push(temp->next[i]); } } } } int query(node *root){ int i=0,cnt=0,index,len=strlen(str); node *p=root; while(str[i]){ index=str[i]-'A'; while(p->next[index]==NULL && p!=root) p=p->fail; p=p->next[index]; p=(p==NULL)?root:p; node *temp=p; while(temp!=root && temp->count!=-1){ cnt+=temp->count; temp->count=-1; temp=temp->fail; } i++; } i=len-1; while(str[i]){ index=str[i]-'A'; while(p->next[index]==NULL && p!=root) p=p->fail; p=p->next[index]; p=(p==NULL)?root:p; node *temp=p; while(temp!=root && temp->count!=-1){ cnt+=temp->count; temp->count=-1; temp=temp->fail; } i--; } return cnt; } int main(){ int n,t; char c; scanf("%d",&t); while(t--){ head=tail=0; node *root=new node(); scanf("%d",&n); while(n--){ scanf("%s",keyword); insert(keyword,root); // reverse(keyword,keyword+strlen(keyword)); // insert(keyword,root); } build_ac_automation(root); int j=0; getchar(); while(c=getchar(),c!='\n') { if(c=='[') { scanf("%d",&n); c=getchar(); for(int i=0;i<n;i++) str[j++]=c; getchar(); } else str[j++]=c; } str[j]='\0'; printf("%d\n",query(root)); } return 0; }