#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+10; struct node{ int cnt; node * nxt[27]; node * fail; vector<node *> num; }*rt; node pool[N]; node *pos[N]; int n,idx; void insert(string s,int x){ node *p=rt; int i; for(i=0;i<s.size();i++){ int sign=s[i]-'a'; if(p->nxt[sign]==NULL) p->nxt[sign]=pool+(++idx); p=p->nxt[sign]; if(i==(int)s.size()-1) pos[x]=p; } } void build(){ int i; queue<node *> q; rt->fail=rt; for(i=0;i<26;i++){ if(rt->nxt[i]){ rt->nxt[i]->fail=rt;//第一次fail等于根 rt->num.push_back(rt->nxt[i]); q.push(rt->nxt[i]); } else{ rt->nxt[i]=rt;//不存在则指向根重新匹配 rt->nxt[i]->fail=rt; } } while(q.size()){ auto t=q.front(); q.pop(); for(i=0;i<26;i++){ if(t->nxt[i]){ t->nxt[i]->fail=t->fail->nxt[i];//存在则最长后缀就是fail指向的最长后缀,因为本身不行 t->fail->nxt[i]->num.push_back(t->nxt[i]);//fail树的存储 q.push(t->nxt[i]); } else{ t->nxt[i]=t->fail->nxt[i];//Trie图,路径压缩思想,直接跳跃到答案 } } } } void dfs(node * p){ int i; for(i=0;i<p->num.size();i++){ node * t=p->num[i]; dfs(t); p->cnt+=t->cnt; } } int main(){ ios::sync_with_stdio(false); cin>>n; int i; rt=pool; for(i=1;i<=n;i++){ string s; cin>>s; insert(s,i); } build();//没有空白位置 string s; cin>>s; node *p=rt; for(i=0;i<s.size();i++){ int x=s[i]-'a'; p=p->nxt[x]; p->cnt++; } dfs(rt); for(i=1;i<=n;i++){ cout<<pos[i]->cnt<<endl; } }