/*
分析:
AC自动机的果题。
好久么有怎么学新算法了,这两天看了点儿新算法。ac自动机去年就接触了囧~~,
不过一直没有看。今儿下午下课后看了下,也敲了下,还行吧,除了因为几天么有怎么
敲题而犯2的在一处很easy的地方wa了一次,其它都还行。
模板题,网上有很多ac自动机的课件呢,其它废话咱就不多说了囧~
2013-04-08
*/
分析:
AC自动机的果题。
好久么有怎么学新算法了,这两天看了点儿新算法。ac自动机去年就接触了囧~~,
不过一直没有看。今儿下午下课后看了下,也敲了下,还行吧,除了因为几天么有怎么
敲题而犯2的在一处很easy的地方wa了一次,其它都还行。
模板题,网上有很多ac自动机的课件呢,其它废话咱就不多说了囧~
2013-04-08
*/
#include"iostream"
#include"cstdio"
#include"cstring"
using namespace std;
const int kind=26;
const int N=10011;
const int M=1000011;
struct node
{
node *child[kind];
node *fail;
int count;
void init()
{
int l;
for(l=0;l<kind;l++) child[l]=NULL;
count=0;
fail=NULL;
}
}*q[50*N];
node *root;
int head,tail;
void insert(char *str)
{
node *now,*next;
int i=0,t;
now=root;
while(str[i])
{
t=str[i]-'a';
if(now->child[t]!=NULL) now=now->child[t];
else
{
next=new node;
next->init();
now->child[t]=next;
now=next;
}
i++;
}
now->count++;
}
void build_fail()
{
int l;
node *now,*p;
head=tail=0;
now=root;
q[tail++]=now;
while(head<tail)
{
now=q[head];
for(l=0;l<kind;l++)
{
if(now->child[l]==NULL) continue;
if(now==root) now->child[l]->fail=root;
else
{
p=now->fail;
while(p!=NULL)
{
if(p->child[l]!=NULL)
{
now->child[l]->fail=p->child[l];
break;
}
p=p->fail;
}
if(p==NULL) now->child[l]->fail=root;
}
q[tail++]=now->child[l];
}
head++;
}
}
int query(char *str)
{
node *now,*temp;
int i,t,cnt;
i=cnt=0;
now=root;
while(str[i])
{
t=str[i]-'a';
while(now->child[t]==NULL && now!=root) now=now->fail;
now=now->child[t];
if(now==NULL) now=root;
temp=now;
while(temp!=NULL && temp->count!=-1) //count+1是针对这个题的小优化
{
cnt+=temp->count; //由于每个单词在str2中重复出现也只能让cnt+1,所以使用过后要标记一下以免重复的给cnt加。
temp->count=-1;
temp=temp->fail;
}
i++;
}
return cnt;
}
int main()
{
int T;
int n;
char str1[55],str2[M];
cin>>T;
while(T--)
{
cin>>n;
root=new node;
root->init();
while(n--) {scanf("%s",str1);insert(str1);}
build_fail();
scanf("%s",str2);
printf("%d\n",query(str2));
}
return 0;
}