#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
int child[240000][26],tot;
int fail[240000],num[240000];
char txt[1000002],s[51];
void ac_insert() //trie树的建立
{
int now=1,i,x,l=strlen(s);
for(i=0;i<l;i++)
{
x=s[i]-'a';
if(!child[now][x])
{
child[now][x]=++tot;
memset(child[tot],0,sizeof(child[tot]));
}
now=child[now][x];
}
num[now]++;
}
void ac_fail() //fail数组,
{
queue<int> q;
int i,fa,p,son;
for(i=0;i<26;i++)
if(child[1][i])
{
fail[child[1][i]]=1; //根节点直接连接的点的fail指向根节点(now=1)
q.push(child[1][i]);
}
fail[1]=0; //根节点的fail为0
while(!q.empty())
{
fa=q.front(),q.pop();
for(i=0;i<26;i++)
{
son=child[fa][i];
if(son)
{
p=fail[fa]; //其他节点沿着它父亲的fail直到找到一个相同字母的
while(p)
{
if(child[p][i])
{
fail[son]=child[p][i];
break;
}
p=fail[p];
}
if(!p) fail[son]=1; //如果没找到,fail就指向根节点
q.push(son);
}
}
}
}
void query()
{
int i,x,temp,now=1,cnt=0,l=strlen(txt);
for(i=0;i<l;i++)
{
x=txt[i]-'a';
while(!child[now][x]&&now!=1) now=fail[now]; //沿着fail一直找,直到到了根节点或者找到了
now=child[now][x];
if(!now) now=1;
temp=now;//temp用来防止遗漏,新的字母增加进来之后,一直找最长后缀来寻找是否有这样的单词。
while(temp!=1)
{
if(num[temp]>=0)
{
cnt+=num[temp];
num[temp]=-1;
}
else break;
temp=fail[temp];
}
}
printf("%d\n",cnt);
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
memset(child[1],0,sizeof(child[1]));
memset(num,0,sizeof(num));
scanf("%d",&n);
tot=1;
while(n--)
{
scanf("%s",s);
ac_insert();
}
memset(fail,0,(tot+1)*sizeof(int));
ac_fail();
scanf("%s",txt);
query();
}
}
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
int child[240000][26],tot;
int fail[240000],num[240000];
char txt[1000002],s[51];
void ac_insert() //trie树的建立
{
int now=1,i,x,l=strlen(s);
for(i=0;i<l;i++)
{
x=s[i]-'a';
if(!child[now][x])
{
child[now][x]=++tot;
memset(child[tot],0,sizeof(child[tot]));
}
now=child[now][x];
}
num[now]++;
}
void ac_fail() //fail数组,
{
queue<int> q;
int i,fa,son;
for(i=0;i<26;i++)
if(child[1][i])
{
fail[child[1][i]]=1; //根节点直接连接的点的fail指向根节点(now=1)
q.push(child[1][i]);
}
else child[1][i]=1;
fail[1]=0; //根节点的fail为0
while(!q.empty())
{
fa=q.front(),q.pop();
for(i=0;i<26;i++)
{
son=child[fa][i];
if(son)
{
fail[son]=child[fail[fa]][i];
q.push(son);
}
else child[fa][i]=child[fail[fa]][i];
}
}
}
void query()
{
int i,temp,now=1,cnt=0,l=strlen(txt);
for(i=0;i<l;i++)
{
now=child[now][txt[i]-'a'];
temp=now;//temp用来防止遗漏,新的字母增加进来之后,一直找最长后缀来寻找是否有这样的单词。
while(temp!=1)
{
if(num[temp]>=0)
{
cnt+=num[temp];
num[temp]=-1;
}
else break;
temp=fail[temp];
}
}
printf("%d\n",cnt);
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
memset(child[1],0,sizeof(child[1]));
memset(num,0,sizeof(num));
scanf("%d",&n);
getchar();
tot=1;
while(n--)
{
gets(s);
ac_insert();
}
memset(fail,0,(tot+1)*sizeof(int));
ac_fail();
gets(txt);
query();
}
}