//AC自动机
//相当于在Trie树上求KMP
//可以求一个字符串的多个匹配子串
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
struct uio{
int son[27],end,fail;//fail指针相当于KMP中的next[]数组
}trie[1000001];
int n,cnt;
char c[1000001];
void insert(char* a)
{
int now=0,len=strlen(a);
for(int i=0;i<len;i++)
{
int c=int(a[i]-'a');
if(!trie[now].son[c])
trie[now].son[c]=++cnt;
now=trie[now].son[c];
}
trie[now].end+=1;
}
void get_fail()//求fail指针
{
queue<int> que;
while(!que.empty()) que.pop();
//将根节点的fail指针预处理出来
//原因是根节点的fail指针指向了根节点自身
//若在BFS中处理会导致其儿子也将fail指针指向儿子自身
for(int i=0;i<26;i++)
if(trie[0].son[i])
{
trie[trie[0].son[i]].fail=0;
que.push(trie[0].son[i]);
}
while(!que.empty())//BFS
{
int now=que.front();
que.pop();
//在取出节点后,正确的操作应为:
//循环26个字母,若不存在儿子则continue
//否则查询:表示字母sth的儿子(下文称sth)的父亲(也就是刚从队列中取出的节点,下文称sth_fa),
//其fail指针指向的节点(下文称sth2_fa)是否也有一个表示字母sth的儿子(下文称sth2)
//若有则直接将sth的fail指针指向sth2
//否则查询sth2_fa的fail指针指向的节点是否也有一个表示字母sth的儿子
//重复以上过程直至找到一个符合条件的儿子或是回溯到root节点
//对于后者直接将sth的fail指针指向root即可
for(int i=0;i<26;i++)
{
if(trie[now].son[i])
{
trie[trie[now].son[i]].fail=trie[trie[now].fail].son[i];
que.push(trie[now].son[i]);
}
else trie[now].son[i]=trie[trie[now].fail].son[i];
}
//那么以上代码为什么正确呢
//考虑分3种情况
//1.有此儿子且第一次查询就找到应指向的节点 则直接指向即可
//2.有此儿子但第一次查询找到了一个空节点 则直接指向即可
//原因是在遇到空节点时会将它的fail指针指向
//其父亲的fail指针指向的节点的表示相同字母的儿子
//这就相当于做了本应在递归过程中进行的操作
//3.无此儿子 这种情况的操作不再赘述
}
}
void query(char* a)
{
int now=0,len=strlen(a);
int ans=0;
for(int i=0;i<len;i++)
{
now=trie[now].son[a[i]-'a'];
for(int j=now;j&&trie[j].end!=-1;j=trie[j].fail)
//未回溯至根节点且未查询过
ans+=trie[j].end,trie[j].end=-1;
}
printf("%d\n",ans);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%s",c),insert(c);
trie[0].fail=0;//标志结束
get_fail();
scanf("%s",c);
query(c);
return 0;
}