#define size 26
char key[1005],dir[5100005];
class ac_auto
{
public:
ac_auto *fail;
ac_auto *next[size];
int cnt;
ac_auto()
{
fail=NULL;
cnt=0;
memset(next,NULL,sizeof(next));
};
void Insert(ac_auto *root,char *str) //构造trie树
{
int i=0,index;
ac_auto *tmp=root;
while(str[i])
{
index=str[i]-'A';
if(tmp->next[index]==NULL)
tmp->next[index]=new ac_auto();
tmp=tmp->next[index];
i++;
}
tmp->cnt++; //单词结尾,计数加1
};
void build(ac_auto *root) //构造自动机
{
queue<ac_auto*> que;
int i;
ac_auto *tmp,*p;
root->fail=NULL;
que.push(root);
while(!que.empty())
{
tmp=que.front();
que.pop();
p=NULL;
for(i=0;i<size;++i)
{
if(tmp->next[i]!=NULL)
{
if(tmp==root) tmp->next[i]->fail=root;
else
{
p=tmp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
tmp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if (p==NULL) tmp->next[i]->fail=root;
}
que.push(tmp->next[i]);
}
}
}
};
int query(char *str,ac_auto *root) //查询,返回之前构造的树中有多少字串出现在str中
{
cnt=0;//不叠加
int i=0,count=0,index,len=strlen(str);
ac_auto *tmp=root,*t;
while(i<len)
{
index=str[i]-'A';
while(tmp->next[index]==NULL && tmp!=root) tmp=tmp->fail;
tmp=tmp->next[index];
if(tmp==NULL) tmp=root;
t=tmp;
while(t!=root && t->cnt!=-1)//避免重复统计,t->cnt==-1的可以直接跳过了,因为之前的子串都肯定被记录了。
{
cnt+=t->cnt;
t->cnt=-1;
t=t->fail;
}
i++;
}
return cnt;
};
};
另附10年福州赛区某题
为了保持模版的封装性,这题可以不用改class的内容的。就是把主串翻转然后再算一次即可。
这题OJ卡的好狠啊……模式串翻转插入就MLE,然后重复统计模式串还会TLE……逼得我不得不把这个偷来的模版类改了改才过的……
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
using namespace std;
#define size 26
char key[1005],dir[5100005];
class ac_auto
{
public:
ac_auto *fail;
ac_auto *next[size];
int cnt;
ac_auto()
{
fail=NULL;
cnt=0;
memset(next,NULL,sizeof(next));
};
void Insert(ac_auto *root,char *str) //构造trie树
{
int i=0,index;
ac_auto *tmp=root;
while(str[i])
{
index=str[i]-'A';
if(tmp->next[index]==NULL)
tmp->next[index]=new ac_auto();
tmp=tmp->next[index];
i++;
}
tmp->cnt++; //单词结尾,计数加1
};
void build(ac_auto *root) //构造自动机
{
queue<ac_auto*> que;
int i;
ac_auto *tmp,*p;
root->fail=NULL;
que.push(root);
while(!que.empty())
{
tmp=que.front();
que.pop();
p=NULL;
for(i=0;i<size;++i)
{
if(tmp->next[i]!=NULL)
{
if(tmp==root) tmp->next[i]->fail=root;
else
{
p=tmp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
tmp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if (p==NULL) tmp->next[i]->fail=root;
}
que.push(tmp->next[i]);
}
}
}
};
int query(char *str,ac_auto *root) //查询,返回之前构造的树中有多少字串出现在str中
{
cnt=0;
int i=0,count=0,index,len=strlen(str);
ac_auto *tmp=root,*t;
while(i<len)
{
index=str[i]-'A';
while(tmp->next[index]==NULL && tmp!=root) tmp=tmp->fail;
tmp=tmp->next[index];
if(tmp==NULL) tmp=root;
t=tmp;
while(t!=root && t->cnt!=-1)
{
cnt+=t->cnt;
t->cnt=-1;
t=t->fail;
}
i++;
}
return cnt;
};
};
int n;
void deal()
{
int i;
int cnt=0,j=0;
memset(dir,0,sizeof(dir));
char tt;
while ((tt=getchar())!='\n')
{
if (tt=='[')
{
int sum=0,ii;
tt=getchar();
while(isdigit(tt))
{
sum=sum*10+(tt-'0');
tt=getchar();
}
char ch=tt;
for (int ii=0;ii<sum;ii++)
dir[cnt++]=ch;
getchar();
}
else if (isalpha(tt))
{
dir[cnt++]=tt;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
ac_auto *ac=new ac_auto;
scanf("%d",&n);
int i,j;
for (i=0;i<n;i++)
{
scanf("%s",key);
ac->Insert(ac,key);
}
getchar();
deal();
ac->build(ac);
int sum=ac->query(dir,ac);
reverse(dir,dir+strlen(dir));
sum+=ac->query(dir,ac);
printf("%d\n",sum);
}
return 0;
}